I've added a new alias scp_using_rsync
, which uses rsync to copy files over SSH with certain options. I wanted to link the bash completion for scp to this alias.
It works when I add this line:
complete -o bashdefault -o default -o nospace -F _scp scp_using_rsync 2>/dev/null || complete -o default -o nospace -F _scp scp_using_rsync
The only problem is that I notice, _scp
gets defined in my bash environment, only after I try tab-completion with ssh/scp at least once in that shell. So if I directly run scp_using_rsync
in a new shell, I would get the _scp
not found error.
The output from typeset -F
in a new shell before and after trying tab completion for ssh or scp commands indicate clearly that the following functions get defined after trying tab-completion for the first time:
$ diff ~/.scratch/file1 ~/.scratch/file2
224a225,227
> declare -f _scp
> declare -f _scp_local_files
> declare -f _scp_remote_files
226a230
> declare -f _sftp
230a235,240
> declare -f _ssh
> declare -f _ssh_ciphers
> declare -f _ssh_macs
> declare -f _ssh_options
> declare -f _ssh_suboption
> declare -f _ssh_suboption_check
These functions seem to be defined in /usr/share/bash-completion/completions/ssh
in my system.
These are my 2 inter-related questions:
- How does bash figure out where to pick up the definitions automatically and define them when the completion is tried for the first time ?
- How should I be linking the bash-completion for
scp_using_rsync
to scp's bash completion in a similar way ?
Bash 4.1
added a new -D
option for complete
, compgen
and compopt
:
New complete/compgen/compopt -D option to define a `default' completion:
a completion to be invoked on command for which no completion has been
defined. If this function returns 124, programmable completion is
attempted again, allowing a user to dynamically build a set of completions
as completion is attempted by having the default completion function
install individual completion functions each time it is invoked.
There's an example from bash's manual:
_completion_loader()
{
. "/etc/bash_completion.d/$1.sh" >/dev/null 2>&1 && return 124
}
complete -D -F _completion_loader
I had an issue applying whjm's answer. As Tuxdude noticed, there was already a function _completion_loader
defined in my distribution (Ubuntu 14.04). The function was defined as follows:
_completion_loader ()
{
local compfile=./completions;
[[ $BASH_SOURCE == */* ]] && compfile="${BASH_SOURCE%/*}/completions";
compfile+="/${1##*/}";
[[ -f "$compfile" ]] && . "$compfile" &> /dev/null && return 124;
complete -F _minimal "$1" && return 124
}
I wanted to make keep the maintenance of the completions all in one place, so I added a file to /usr/share/bash-completion/completions/
with the name of the command I wanted to add completion for. For your case, you could add a file called scp_using_rsync
containing this:
cfile="${compfile%/*}/scp"
cmd="${1##*/}"
. "$cfile"
complete -F _scp $cmd
This will source the file that defines completions for scp
, including the _scp
function, and then add the completion for your command. I felt this is a more direct and consistent way (though of course to do this, you must be ok with changing this behavior for all users.)
Some completion functions are dynamically loaded. You can manually load them so that they will work with aliases. For example, you can add this to your ~/.bashrc
so that completion will work with your alias.
_completion_loader docker