bash – How Does Bash Know When to Do Filename Expansion?

autocompletebash

Typing ssh-copy-id -i ~/.ssh/, then Tab causes filename expansion, which lists all files in ~/.ssh.

Typing ssh-copy-id without the -i flag, then Spacebar, Tab doesn't cause file expansion.

Typing ssh-copy-id -x, Spacebard, Tab(note that -x is an invalid flag) also does not lead to file expansion.

How does Bash "know" to do file expansion after typing -i? Does the program ssh-copy-id have to be programmed in a way to let Bash know to do it? I read this page and others on filename expansion but could not find an answer for my question:
https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html

Bash version:
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

Best Answer

Tab-completion is different from filename expansion.

Tab-completion is a native feature of Bash GNU Readline for interactive Bash sessions. For example, it completes variables (try echo $SH<TAB>) and also commands arguments with file names.

Additionally, if bash-completion package is installed, the completion becomes more intelligent for the commands comprised in in /usr/share/bash-completion/completions, one of which is ssh-copy-id. Since the -i flag for ssh-copy-id requires a file, it tab-completes files. Without -i, there does not make sense to supply a file, so no completion is performed.

Again, that is only true for commands in the completions directory. If you have a foobar command that does not accept a file as an argument, Bash will still complete with files because bash-completion has no idea of foobar.

On the other hand, filename expansion is a POSIX shell behavior. It occurs regardless of whether the shell is interactive or not. Example: ssh-copy-id -x * causes * to expand to all files in the current directory, the command wanting them or not.

Related Question