When I use program like svn
and I type in Gnome Terminal:
svn upd
and hit Tab it's autocompleted to:
svn update
Is it possible to do something like that in my custom bash script?
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It only takes a minute to sign up.
Sign up to join this communityWhen I use program like svn
and I type in Gnome Terminal:
svn upd
and hit Tab it's autocompleted to:
svn update
Is it possible to do something like that in my custom bash script?
You'll have to create a new file:
/etc/bash_completion.d/foo
For a static autocompletion (--help
/ --verbose
for instance) add this:
_foo()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="--help --verbose --version"
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
complete -F _foo foo
COMP_WORDS
is an array containing all individual words in the current command line.COMP_CWORD
is an index of the word containing the current cursor position.COMPREPLY
is an array variable from which Bash reads the possible completions.And the compgen
command returns the array of elements from --help
, --verbose
and --version
matching the current word "${cur}"
:
compgen -W "--help --verbose --version" -- "<userinput>"
-
and show them without having to start typing the target word, just remove the if [...] then
and fi
lines.
Sep 16, 2015 at 9:23
~/.local/share/bash-completion/completions/
after creating it. System completion scripts are generally stored in /usr/share/bash-completion/completions/
.
Nov 28, 2020 at 15:52
~/.local/share/bash-completion/completions/
, they do not automatically get sourced. It's no different than if they're at ~/my/completion/dir
. Not a big deal, I just source them manually either way.
Dec 17, 2021 at 21:41
/etc/bash_completion.d/
gets automatically loaded according to other links here, but I don't see anything about ~/.local
. I know that's an XDG thing, but I guess I just suck at google-fu because I cannot find anything about automatic sourcing from the share/bash-completion/completions
directory.
Dec 17, 2021 at 21:42
Here is a complete tutorial.
Let's have an example of script called admin.sh
to which you would like to have autocomplete working.
#!/bin/bash
while [ $# -gt 0 ]; do
arg=$1
case $arg in
option_1)
# do_option_1
;;
option_2)
# do_option_2
;;
shortlist)
echo option_1 option_2 shortlist
;;
*)
echo Wrong option
;;
esac
shift
done
Note the option shortlist
. Calling the script with this option will print out all possible options for this script.
And here you have the autocomplete script:
_script()
{
_script_commands=$(/path/to/your/script.sh shortlist)
local cur
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=( $(compgen -W "${_script_commands}" -- ${cur}) )
return 0
}
complete -o nospace -F _script ./admin.sh
Note that the last argument to complete is the name of the script you want to add autocompletion to. All you need to do is to add your autocomplete script to bashrc as :
source /path/to/your/autocomplete.sh
or copy it to :
/etc/bash_completion.d
~/.local/share/bash-completion/completions/
; this directory can be created by the user. System completion scripts are generally stored in /usr/share/bash-completion/completions/
.
Nov 28, 2020 at 16:00
You can use the Programmable Completion. Have look at /etc/bash_completion
and /etc/bash_completion.d/*
for some examples.
/usr/share/bash-completion/completions/<program>
Sep 26, 2017 at 21:26
The provided link has that already
- it might today, but it mightn't tomorrow. Or next year. Or in a decade. Whatever you might suggest about the documentation still being relevant, Stack Overflow discourages link-only answers for these reasons.
Jan 20, 2019 at 9:23
All of the bash completions are stored in /etc/bash_completion.d/
. So if you're building software with bash_completion it would be worthwhile to have the deb/make install drop a file with the name of the software in that directory. Here's an example bash completion script for Rsync:
# bash completion for rsync
have rsync &&
_rsync()
{
# TODO: _split_longopt
local cur prev shell i userhost path
COMPREPLY=()
cur=`_get_cword`
prev=${COMP_WORDS[COMP_CWORD-1]}
_expand || return 0
case "$prev" in
--@(config|password-file|include-from|exclude-from))
_filedir
return 0
;;
-@(T|-temp-dir|-compare-dest))
_filedir -d
return 0
;;
-@(e|-rsh))
COMPREPLY=( $( compgen -W 'rsh ssh' -- "$cur" ) )
return 0
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W '-v -q -c -a -r -R -b -u -l -L -H \
-p -o -g -D -t -S -n -W -x -B -e -C -I -T -P \
-z -h -4 -6 --verbose --quiet --checksum \
--archive --recursive --relative --backup \
--backup-dir --suffix= --update --links \
--copy-links --copy-unsafe-links --safe-links \
--hard-links --perms --owner --group --devices\
--times --sparse --dry-run --whole-file \
--no-whole-file --one-file-system \
--block-size= --rsh= --rsync-path= \
--cvs-exclude --existing --ignore-existing \
--delete --delete-excluded --delete-after \
--ignore-errors --max-delete= --partial \
--force --numeric-ids --timeout= \
--ignore-times --size-only --modify-window= \
--temp-dir= --compare-dest= --compress \
--exclude= --exclude-from= --include= \
--include-from= --version --daemon --no-detach\
--address= --config= --port= --blocking-io \
--no-blocking-io --stats --progress \
--log-format= --password-file= --bwlimit= \
--write-batch= --read-batch= --help' -- "$cur" ))
;;
*:*)
# find which remote shell is used
shell=ssh
for (( i=1; i < COMP_CWORD; i++ )); do
if [[ "${COMP_WORDS[i]}" == -@(e|-rsh) ]]; then
shell=${COMP_WORDS[i+1]}
break
fi
done
if [[ "$shell" == ssh ]]; then
# remove backslash escape from :
cur=${cur/\\:/:}
userhost=${cur%%?(\\):*}
path=${cur#*:}
# unescape spaces
path=${path//\\\\\\\\ / }
if [ -z "$path" ]; then
# default to home dir of specified
# user on remote host
path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null)
fi
# escape spaces; remove executables, aliases, pipes
# and sockets; add space at end of file names
COMPREPLY=( $( ssh -o 'Batchmode yes' $userhost \
command ls -aF1d "$path*" 2>/dev/null | \
sed -e 's/ /\\\\\\\ /g' -e 's/[*@|=]$//g' \
-e 's/[^\/]$/& /g' ) )
fi
;;
*)
_known_hosts_real -c -a "$cur"
_filedir
;;
esac
return 0
} &&
complete -F _rsync $nospace $filenames rsync
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh
It would likely be worthwhile to review one of the bash completion files in there that most closely matches your program. One of the simplest examples is the rrdtool
file.
source ~/.local/mycrazycompletion
in your ~/.bashrc
Mar 22, 2016 at 5:40
pkg-c
onfig --variable=completionsdir bash-completion` and that directory is the recommendation given by Bash Completion FAQ linked above.
~/.local/share/bash-completion/completions/
; this directory can be created by the user. System completion scripts are generally stored in /usr/share/bash-completion/completions/
.
Nov 28, 2020 at 16:02
If all you want is a simple word based auto-completion (so no subcommand completion or anything), the complete
command has a -W
option that just does the right thing.
For example, I have the following lines in my .bashrc
to autocomplete a program called jupyter:
# gleaned from `jupyter --help`
_jupyter_options='console qtconsole notebook' # shortened for this answer
complete -W "${_jupyter_options}" 'jupyter'
Now jupyter <TAB> <TAB>
autocompletes for me.
The docs at gnu.org are helpful.
It does seem to rely on the IFS
variable being set correctly, but that hasn't caused any issues for me.
To add filename completion and default BASH completion, use the -o
option:
complete -W "${_jupyter_options}" -o bashdefault -o default 'jupyter'
To use this in zsh, add the following code before running the complete
command in your ~/.zshrc
:
# make zsh emulate bash if necessary
if [[ -n "$ZSH_VERSION" ]]; then
autoload bashcompinit
bashcompinit
fi
Just adding this here in case it helps anyone.
Examples aside, the definitive source/reference to learn more about this topic is the bash manual itself (i.e. type man bash
in a terminal)
Search for headings "Completing" and "Programmable Completion". (in the current version of the bash documentation, these appear around lines 2219 and 2332 respectively), and also the relevant bash builtin keywords referenced in those sections (e.g. compgen (line 2627), complete (line 2637), etc)
None of these answers gave me the 'type some random stuff and it just works' feel I was looking for so I used a different approach that I think works much better using fzf (sudo apt install fzf
)
Let's take a simple case first.
Let's say we want to echo some word from a dictionary (/usr/share/dict/words
) with auto-suggestions of the words.
We can do this with this bash function:
function ppp(){ echo "Your word is: $(cat /usr/share/dict/words | fzf -q "$1" --prompt "hi> ")";};
Paste that into your shell then try:
ppp fuzz [hit enter]
Choose your word by typing more letters or using arrow keys, hit enter, and:
Your word is: fuzzball
Perfect.
Now let's take a more interesting example - let's do auto-completion for a package.json
file's "script" commands
First sudo apt get install jq fzf
then copy/paste this function:
function ppp(){ pnpm $(jq -r ".scripts|keys[]"<$(pnpm root|sed 's/node_modules//')package.json|fzf -q "$1" --prompt "pnpm> ");};
Now go into a node project folder (or subfolder) and
ppp tes
This works for anything for the pattern of filter/choose/run command.
Add the function to your .bashrc and happy days.