When I type
unzip <tab>
I get a list of all files ending in .zip
, which is the standard behavior of tab completion for the unzip
command.
However, I also want bash completion for unzip
list files which end in .udp
, in addition to .zip
files. How can I achieve this behavior in my local .bashrc
?
4 Answers 4
Instead of keeping on commenting ...
complete -f -X '!*.@(zip|udp)' unzip
should add completion for
-f -X '!*.@(zip|udp)'
| | | |||________|
| | | || |
| | | || +- filterpat: zip or udp
| | | |+------------- @ : Matches one of the given patterns
| | | +-------------- *. : Anything+<dot>
| | +---------------- ! : Negate
| +------------------- -X : Filter out matches in "filterpat"
+---------------------- -f : files
In other words: Complete files and remove all not ending in .zip
or .udp
.
Extras
If you add -o default
completion will complete/match all files and directories if there is no files ending in .zip
or .udp
.
If you add -o plusdirs
completion will add any directories in addition to any matches of files ending in .zip
or .udp
.
Current
When you use complete -p unzip
you get current pattern.
From your comments it sounds mostly like you are missing either +
or @
in pattern, as in:
# Err:
complete -f -X '!*.(zip|udp)' unzip
|
+---- Missing + or @
which would mean match any file literally ending in .(zip|udp)
. E.g.
touch 'file_test.(zip|udp)'
Also have a look at this section of the manual:
it is possible e.g. extglob
is not enabled. Enable by:
shopt -s extglob
Check current status of all shopt
settings by entering:
shopt
Function
If that is -F something
it means it uses a function named something to generate the list of completions.
The _filedir_xspec
is typically a Debian function. You might have something like this:
$ cat /etc/bash_completion
. /usr/share/bash-completion/bash_completion
Which means /usr/share/bash-completion/bash_completion
get sourced. Here you'll find the function in question. A few lines further down you see that this function / completion is added by a function named _install_xspec
by e.g.:
_install_xspec '!*.@(zip|[ejsw]ar|exe|pk3|wsz|zargo|xpi|s[tx][cdiw]|sx[gm]|o[dt][tspgfc]|od[bm]|oxt|epub|apk|do[ct][xm]|p[op]t[mx]|xl[st][xm])' unzip zipinfo
Manual entries:
Update to comments 1:
– No match due to invalid archives or file permissions.
This should not affect the result. complete
only matches files given by the rules and do no processing of the files. If you can list them with ls
, they should match.
As a side note one could add such a functionality by using a complete function:
function _unzip_validated() {
# 1. Generate list of files ending in e.g. .zip and .udp
# 2. Validate each file and remove invalid ones from file list.
}
complete -F _unzip_validated unzip
– Colors. Why does ls
distinguish test.zip
from test.upd
?
This does not affect complete
. Colors by ls
are provided by $LS_COLORS
. Try:
echo "$LS_COLORS" | tr : '\n' | sort
You should see something like *.zip=01;31
which means:
*.zip=01;31
|____| | |
| | +--- Red
| +------ Bold
+---------- Files with .zip extension
*.udp
on the other hand has no entry associated with it, so no coloring.
Next step (should have been first)
- Open terminal and go to a directory with test files. Both .zip and .udp
- Enter
bash --norc
- Enter
complete -f -X '!*.@(zip|udp)' unzip
- Enter
shopt -s extglob
- Enter
unzip <tab><tab>
Result?
Also, click edit below your question and add output of:
bind -V
shopt
env
might be helpful.
-
Thank you very much for your excellent and lengthy explanation, but still it does not work.
complete -p unzip
yieldscomplete -f -X '!*.@(zip|udp)' unzip
, andunzip <tab>
completes the file namedtest.zip
. However, the directory contains a file namedtest.upd
as well which is not found by tab completion ofunzip
. Do the fact of file permissions or a zero length of the file maybe explain this weird behavior?Alex– Alex2014年01月10日 06:01:45 +00:00Commented Jan 10, 2014 at 6:01 -
@Alex: Should get completion on both empty and valid files, as well as on files where one do not have permission. Is it the same behavior if you add it to a test script? E.g. 1. some test script with execution set:
~/bin/testing
, 2.complete -f -X '!*.@(zip|udp)' testing
, 3.testing <tab><tab>
?Runium– Runium2014年01月10日 06:22:10 +00:00Commented Jan 10, 2014 at 6:22 -
@Alex: You could also update Q with output of
shopt
...Runium– Runium2014年01月10日 09:27:00 +00:00Commented Jan 10, 2014 at 9:27 -
extglob
is activated. The example with 'testing' selects thezip
file only again. I notice thattest.zip
is shown in red color, whiletest.upd
is shown in white color withls -l
, both files empty with same permissions, ownershift and group association. Why doesls
distinguishtest.zip
fromtest.upd
? Maybe this is a hint towards the problem I have?Alex– Alex2014年01月10日 12:19:40 +00:00Commented Jan 10, 2014 at 12:19 -
In the file /etc/bash_completion
, which you are presumably sourcing somewhere, the default completion, at least for my version of bash
(v4.2.25) is
complete -f -X '!*.@(zip|[ejw]ar|exe|pk3|wsz|zargo|xpi|sxw|o[tx]t|od[fgpst]|epub|apk)' unzip zipinfo
Try changing the entire expression to
complete -f -X '!*.@(zip|[ejw]ar|exe|pk3|wsz|zargo|xpi|sxw|o[tx]t|od[fgpst]|epub|apk|udp)' unzip zipinfo
And add to your .bash_profile
-
This does not solve my problem. If I do so and source it,
unzip <tab>
neither finds.zip
nor.upd
files nor other files.Alex– Alex2014年01月09日 06:08:53 +00:00Commented Jan 9, 2014 at 6:08 -
Try hitting tab twice, see if that's any different. Do other completions work as expected? For example
gzip
with.gz
files?bsd– bsd2014年01月09日 11:54:01 +00:00Commented Jan 9, 2014 at 11:54 -
Hitting tab twice does not change anything. Using
gunzip
with.gz
files select only files ending in.gz
, but the definition is also different:complete -F _filedir_xspec gunzip
.Alex– Alex2014年01月09日 12:35:30 +00:00Commented Jan 9, 2014 at 12:35 -
Do you source the file
/etc/bash_completion
in your.bashrc
?bsd– bsd2014年01月09日 18:27:21 +00:00Commented Jan 9, 2014 at 18:27 -
Try
shopt -s extglob
Edward Falk– Edward Falk2016年06月24日 01:07:40 +00:00Commented Jun 24, 2016 at 1:07
Try adding this line in your .bashrc:
complete -f -o default -X '!*.+(zip|udp)' unzip
-
It seems with this suggestion I will find
.udp
files, but only if no.zip
files are present. If atest.zip
andtest.udp
file is present in the current directory,unzip <tab>
only lists the.zip
file. I would expect to see both files (i.e. the bash completion would givetest.
).Alex– Alex2014年01月08日 16:36:03 +00:00Commented Jan 8, 2014 at 16:36 -
Are you sure? I checked on my bash and I seem to find both
udp
andzip
files. Did you source.bashrc
after adding the line?Ketan– Ketan2014年01月08日 16:43:55 +00:00Commented Jan 8, 2014 at 16:43 -
I repeated in a new terminal, and now
unzip <tab>
list all files, even ones ending in a different phrase. Now quite what I need.Alex– Alex2014年01月08日 16:51:48 +00:00Commented Jan 8, 2014 at 16:51 -
Strange.. I am running GNU bash version 4.2.25 and works as expected. Which version of bash are you on?Ketan– Ketan2014年01月08日 17:02:04 +00:00Commented Jan 8, 2014 at 17:02
-
Could you try adding two separate lines:
complete -f -o default -X '!*.zip' unzip
andcomplete -f -o default -X '!*.udp' unzip
Ketan– Ketan2014年01月08日 17:06:45 +00:00Commented Jan 8, 2014 at 17:06
Better use _filedir
instead of "raw" complete
.
Justification
grep _filedir -r $(pkg-config --variable=completionsdir bash-completion) | wc -l
- tilde (
~
) paths are being expanded - Prefixes are removed for directories, i.e. for
/home/tux/Do<TAB><TAB>
, the list you get as a reply removes '/home/tux' and is thus much more compact - Easier to implement and more failsafe
MWE
_unzip_completor()
{
# init bash-completion's stuff
_init_completion || return
# fill COMPREPLY using bash-completion's routine
_filedir '@(zip|udp)'
}
complete -F _unzip_completor unzip