When I start typing something into an interactive login shell (zsh or bash) and click tab, the shell offers me autocomplete suggestions.
I broadly understand how completion specs are defined. For reference it's outlined here:
- Bash: https://www.gnu.org/software/bash/manual/bash.html#Programmable-Completion
- Zsh: http://zsh.sourceforge.net/Doc/Release/Completion-System.html
What I don't understand is how bash/zsh identify which command to complete on when a user presses tab i.e. if I do ls [tab]
, how does bash/zsh identify ls
. Put differently, how do bash/zsh know to generate completions using the ls
completion spec.
Some more examples with more complicated parsing which Bash/Zsh still get right:
ls [tab]
-> completes onls
echo $( echo $(ls [tab]
-> completes onls
echo hi; git a[tab]
-> completes ongit
echo 'cd [tab]
-> does NOT complete oncd
echo "$(ls [tab]
-> completes onls
echo $( echo hi | ls [tab]
-> completes onls
(I knowls
doesn't take stdin but this example still illustrates bash/zsh's parsing abilities)
I am presuming bash/zsh are using some sort of parser. However, it's not a normal parser. It completes without a properly structured command. It is aware that something is in quotes or a shell expansion, even if they are not closed.
What function is bash/zsh running to "identify" the relevant command or determine whether or not there is a command to complete on at all?
echo $(ls [TAB])
/etc/bash_completion.d
and/usr/share/bash-completion/completions
are pretty self-explanatory. 1. You define a completion function via:complete -F _function_name application_name
i.e.complete -F _ls ls
2. Then you define function _function_name which expands values.$PATH
. This is used for completion. See therehash
builtin inman bash
.ls
inecho $(ls ( ) )
and press tab, it auto completes even when the code to the right is invalid syntax.