bash does not autocomplete my command when using sudo?
Solution 1
Check set -o
to see if maybe posix
mode is enabled. If so, disable with set +o posix
In "posix" mode, bash's tab-completion is for some reason disabled in "vi-mode". I've not seen any explanation why this behavior is so, nor why it's specific to vi-mode, so I didn't bother explaining.
PS: This answer is more suited for someone who stumbles upon the question via a search engine... not for your particular setup.
Update:
Chet Ramey says:
in POSIX mode, the vi editing mode should not map tab to complete. This is because POSIX.2 completely specifies the behavior of the vi editing mode, and the standard requires tab to be mapped to self insert by default.
Solution 2
Quick answer:
- Install
bash-completion
- Source
bash_completion
onBash
startup - Add your compspec on
Bash
startup - Don't overwrite
sudo
compspec withcomplete -cf sudo
I suppose that you use MacOSX
with brew
.
Try:
brew update
brew install bash-completion
brew info bash-completion
# bash-completion: stable 1.3
. $(brew --prefix)/etc/bash_completion
complete -p sudo
You should see something like this:
complete -F _root_command sudo
Test:
function _comp_foo() { COMPREPLY=($(compgen -W 'a b c' -- "$2")); }
complete -F _comp_foo foo
Type foo
SpaceTabTab
You should see a b c
Type sudo foo
SpaceTabTab
You should see a b c
Then remove complete -fc sudo
from your initialisation files (~/.bash_profile
, ~/.bashrc
etc)
Add the following lines to your initialisation files:
if [ -f $(brew --prefix)/etc/bash_completion ]; then
. $(brew --prefix)/etc/bash_completion
fi
# Your compspec here
complete -o default -o nospace -W "$(sudo ls -1 /var/cache/salt/master/minions)" salt
Reopen terminal.
Type complete -p sudo
.
You should see complete -F _root_command sudo
.
Type complete -p salt
.
You should see something like this:
complete -o default -o nospace -W 'a
b
c' salt
bash-completion2.* note:
You can install bash-completion2
: https://github.com/Homebrew/homebrew/issues/19258
But:
-
2.*
works withBash 4.*
-
2.*
uses the-D
option for compspecs lazy loading. So,complete -p sudo
outputscomplete: sudo: no completion specification
until you typesudo
SpaceTab
Nathan Hangen
Updated on September 18, 2022Comments
-
Nathan Hangen over 1 year
I'm using SaltStack. I would like to auto-complete the minion name when calling the
salt
command.The following line has been added into
~/.bashrc
:complete -o default -o nospace -W "$(sudo ls -1 /var/cache/salt/master/minions)" salt
Then typing
salt inTab
→salt integration-Tab
; I can see it works as expected:$ salt integration-TabTab integration-c integration-u integration-u2
To use with
sudo
, I have addedcomplete -cf sudo
into~/.bashrc
, but it didn't work:sudo salt inTab
returned nothing.
I also have tried to install
bash_completion
and added the following lines to~/.bash_profile
:if [ -f $(brew --prefix)/etc/bash_completion ]; then . $(brew --prefix)/etc/bash_completion fi
but no luck.
Did I miss something?
Update
Oh, the first thing I would like to say is sometimes it works:
$ sudo salt integration-TabTab integration-c integration-u integration-u2
and sometimes it doesn't.
So first, let's see how much your bash_completion package does.
How can I check that? Here's my function:
# a wrapper method for the next one, when the offset is unknown _command() { local offset i # find actual offset, as position of the first non-option offset=1 for (( i=1; i <= COMP_CWORD; i++ )); do if [[ "${COMP_WORDS[i]}" != -* ]]; then offset=$i break fi done _command_offset $offset } # A meta-command completion function for commands like sudo(8), which need to # first complete on a command, then complete according to that command's own # completion definition - currently not quite foolproof (e.g. mount and umount # don't work properly), but still quite useful. # _command_offset() { local cur func cline cspec noglob cmd i char_offset word_offset \ _COMMAND_FUNC _COMMAND_FUNC_ARGS word_offset=$1 # rewrite current completion context before invoking # actual command completion # find new first word position, then # rewrite COMP_LINE and adjust COMP_POINT local first_word=${COMP_WORDS[$word_offset]} for (( i=0; i <= ${#COMP_LINE}; i++ )); do if [[ "${COMP_LINE:$i:${#first_word}}" == "$first_word" ]]; then char_offset=$i break fi done COMP_LINE=${COMP_LINE:$char_offset} COMP_POINT=$(( COMP_POINT - $char_offset )) # shift COMP_WORDS elements and adjust COMP_CWORD for (( i=0; i <= COMP_CWORD - $word_offset; i++ )); do COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]} done for (( i; i <= COMP_CWORD; i++ )); do unset COMP_WORDS[i]; done COMP_CWORD=$(( $COMP_CWORD - $word_offset )) COMPREPLY=() _get_comp_words_by_ref cur if [[ $COMP_CWORD -eq 0 ]]; then _compopt_o_filenames COMPREPLY=( $( compgen -c -- "$cur" ) ) else cmd=${COMP_WORDS[0]} if complete -p ${cmd##*/} &>/dev/null; then cspec=$( complete -p ${cmd##*/} ) if [ "${cspec#* -F }" != "$cspec" ]; then # complete -F <function> # get function name func=${cspec#*-F } func=${func%% *} if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}" else $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" fi # remove any \: generated by a command that doesn't # default to filenames or dirnames (e.g. sudo chown) # FIXME: I'm pretty sure this does not work! if [ "${cspec#*-o }" != "$cspec" ]; then cspec=${cspec#*-o } cspec=${cspec%% *} if [[ "$cspec" != @(dir|file)names ]]; then COMPREPLY=("${COMPREPLY[@]//\\\\:/:}") else _compopt_o_filenames fi fi elif [ -n "$cspec" ]; then cspec=${cspec#complete}; cspec=${cspec%%${cmd##*/}}; COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) ); fi elif [ ${#COMPREPLY[@]} -eq 0 ]; then _filedir fi fi }
if you type
sudo mkdir
TabTab, does it show a list of directories?Yes:
$ sudo mkdir TabTab .FontForge/ .djangopypi2/ .ievms/ .ssh/ .wireshark-etc/
-
Mark Plotnick almost 10 yearsChaining together command completions usually involves completion functions that invoke a function defined in the completion package called
_command_offset
. So first, let's see how much your bash_completion package does. If you remove thecomplete -cf sudo
line from .bashrc, then logout and login again, and just use the support built in to bash_completion, do you see any special handling at all for sudo, e.g., if you typesudo mkdir <tab><tab>
, does it show a list of directories? -
Nathan Hangen almost 10 years@MarkPlotnick: if you type sudo
mkdir <tab><tab>
, does it show a list of directories? --> Yes, see my update in the original question. -
Mark Plotnick almost 10 yearsIf completion chaining is sometimes working and sometimes not, the first thing I'd check is the completion definition for
sudo
when completions are not working. Do this by typingcomplete|grep sudo
. Bash on OSX reads its init files in nonintuitive ways (see apple.stackexchange.com/a/13019), so my hunch is that sometimes not all your completion definitions are being read in or they are being superseded by unwanted definitions. -
G-Man Says 'Reinstate Monica' almost 9 yearsPossibly related: How does Bash path completion work with sudo?
-
-
Evgeny Vereshchagin almost 9 yearsQuestion about bash completion on posix mode