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?


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.


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.


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:



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:

|____| |  |
   |   |  +--- 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)

  1. Open terminal and go to a directory with test files. Both .zip and .udp
  2. Enter bash --norc
  3. Enter complete -f -X '!*.@(zip|udp)' unzip
  4. Enter shopt -s extglob
  5. Enter unzip <tab><tab>


Also, click edit below your question and add output of:

bind -V

might be helpful.

| improve this answer | |
  • Thank you very much for your excellent and lengthy explanation, but still it does not work. complete -p unzip yields complete -f -X '!*.@(zip|udp)' unzip, and unzip <tab> completes the file named test.zip. However, the directory contains a file named test.upd as well which is not found by tab completion of unzip. Do the fact of file permissions or a zero length of the file maybe explain this weird behavior? – Alex Jan 10 '14 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 Jan 10 '14 at 6:22
  • @Alex: You could also update Q with output of shopt – Runium Jan 10 '14 at 9:27
  • extglob is activated. The example with 'testing' selects the zip file only again. I notice that test.zip is shown in red color, while test.upd is shown in white color with ls -l, both files empty with same permissions, ownershift and group association. Why does ls distinguish test.zip from test.upd? Maybe this is a hint towards the problem I have? – Alex Jan 10 '14 at 12:19
  • @Alex: Added an update. – Runium Jan 11 '14 at 0:09

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

| improve this answer | |
  • 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 Jan 9 '14 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 Jan 9 '14 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 Jan 9 '14 at 12:35
  • Do you source the file /etc/bash_completion in your .bashrc ? – bsd Jan 9 '14 at 18:27
  • Try shopt -s extglob – Edward Falk Jun 24 '16 at 1:07

Try adding this line in your .bashrc:

complete -f -o default -X '!*.+(zip|udp)' unzip
| improve this answer | |
  • It seems with this suggestion I will find .udp files, but only if no .zip files are present. If a test.zip and test.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 give test.). – Alex Jan 8 '14 at 16:36
  • Are you sure? I checked on my bash and I seem to find both udp and zip files. Did you source .bashrc after adding the line? – mkc Jan 8 '14 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 Jan 8 '14 at 16:51
  • Strange.. I am running GNU bash version 4.2.25 and works as expected. Which version of bash are you on? – mkc Jan 8 '14 at 17:02
  • Could you try adding two separate lines: complete -f -o default -X '!*.zip' unzip and complete -f -o default -X '!*.udp' unzip – mkc Jan 8 '14 at 17:06

Better use _filedir instead of "raw" complete.


  • 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


    # init bash-completion's stuff
    _init_completion || return

    # fill COMPREPLY using bash-completion's routine
    _filedir '@(zip|udp)'
complete -F _unzip_completor unzip
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.