Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 3

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)

  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>

Result?

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

bind -V
shopt
env

might be helpful.

share|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 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> ? –  Sukminder Jan 10 at 6:22
    
@Alex: You could also update Q with output of shopt –  Sukminder Jan 10 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 at 12:19
    
@Alex: Added an update. –  Sukminder Jan 11 at 0:09

Try adding this line in your .bashrc:

complete -f -o default -X '!*.+(zip|udp)' unzip
share|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 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? –  Ketan Jan 8 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 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 Jan 8 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 –  Ketan Jan 8 at 17:06

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

share|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 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? –  bdowning Jan 9 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 at 12:35
    
Do you source the file /etc/bash_completion in your .bashrc ? –  bdowning Jan 9 at 18:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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