I've noticed a really cool feature of bash-completion in bash. Let's say I have a directory with files
a.java
a.class
b.java
b.class
if I start typing vim a
Tab , bash will autocomplete a.java
. It knows I don't want to edit a.class
I was wondering how it achieves this behavior. In my bash_completion.d
directory there are a bunch of completion
files, but vim
does not have one.
How does vim
achieve this behavior, and how do I modify it to include other file extensions to ignore?
On Ubuntu, if I install the package bash-completion
, I can see its contents with:
$ dpkg -L bash-completion
In the output, /etc/bash_completion
is listed.
Inside, the following command is written:
. /usr/share/bash-completion/bash_completion
It sources the file /usr/share/bash-completion/bash_completion
.
The location of these files vary from an OS to another:
Note: I use a Mac, and on macOS the bash-completion file is stored (by default) in /usr/local/etc/bash_completion
, and the bash_completion.d
directory is in /usr/local/etc/bash_completion.d
On my system, /usr/share/bash-completion/bash_completion
contains this line:
_install_xspec '*.@(o|so|so.!(conf|*/*)|a|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite
I think this line is responsible for the behavior you're observing.
If you want to tweak it to make bash exclude the foo
and bar
extensions when completing a filename after the $ vim
command, you could try the following procedure.
- Create the file
~/.bash_completion
Inside the latter, write:
for bcfile in ~/.bash_completion.d/* ; do
[ -f "$bcfile" ] && . $bcfile
done
Create the ~/.bash_completion.d/
directory.
Inside this directory, create a vim
file.
Inside the latter, write:
complete -f -X '*.@(o|so|so.!(conf|*/*)|a|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class|foo|bar)' vi vim gvim rvim view rview rgvim rgview gview
complete
is a bash builtin command which allows you to specify how arguments to a command name should be completed.
-f
is a shorthand for -A file
, which specifies to bash that you want to see only filenames in your suggestions.
-X
excludes anything which matches the following pattern.
Note that I have merely copied the pattern used in /usr/share/bash-completion/bash_completion
, and added the foo
and bar
extensions:
*.@(o|so|so.!(conf|*/*)|a|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class|foo|bar)
^^^^^^^
It's up to you to modify the pattern to exclude the real extensions you want to avoid.
The names after the pattern tell bash for which commands should it exclude these extensions.
In the previous command, they are:
vi vim gvim rvim view rview rgvim rgview gview
All of them invoke a version of Vi or Vim. You could add other editor names at the end.
For more information see:
$ man bash
Look for the READLINE
section and the Programmable Completion
subsection, as well as the description of the complete
builtin in the SHELL BUILTIN COMMANDS
section.
See also An introduction to bash completion part 1 and An introduction to bash completion part 2.