diff --git a/bash_completion b/bash_completion index 31529920c7f..d56097046c7 100644 --- a/bash_completion +++ b/bash_completion @@ -2111,33 +2111,44 @@ _included_ssh_config_files() local configfile i files f configfile=$1 + # From man ssh_config: + # "Files without absolute paths are assumed to be in ~/.ssh if included + # in a user configuration file or /etc/ssh if included from the system + # configuration file." + # This behavior is not affected by the the including file location - + # if the system configuration file is included from the user's config, + # relative includes are still resolved in the user's ssh config directory. + local relative_include_base + if [[ $configfile == /etc/ssh* ]]; then + relative_include_base="/etc/ssh" + else + relative_include_base="$HOME/.ssh" + fi + + local depth=1 local -a included - _comp_split included "$(command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\(.*\)$/\1/p' "${configfile}")" || return - - for i in "${included[@]}"; do - # Check the origin of $configfile to complete relative included paths on included - # files according to ssh_config(5): - # "[...] Files without absolute paths are assumed to be in ~/.ssh if included in a user - # configuration file or /etc/ssh if included from the system configuration file.[...]" - if ! [[ $i =~ ^\~.*|^\/.* ]]; then - if [[ $configfile =~ ^\/etc\/ssh.* ]]; then - i="/etc/ssh/$i" - else - i="$HOME/.ssh/$i" + local -a include_files + included=("$configfile") + + while ((${#included[@]} > 0 && depth++ < 16)); do + _comp_split include_files "$(command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\(.*\)$/\1/p' "${included[@]}")" || return + included=() + for i in "${include_files[@]}"; do + if [[ $i != [~/]* ]]; then + i="${relative_include_base}/${i}" fi - fi - __expand_tilde_by_ref i - # In case the expanded variable contains multiple paths - _comp_expand_glob files '$i' - if ((${#files[@]})); then - for f in "${files[@]}"; do - if [[ -r $f && ! -d $f ]]; then - config+=("$f") - # The Included file is processed to look for Included files in itself - _included_ssh_config_files "$f" - fi - done - fi + __expand_tilde_by_ref i + # In case the expanded variable contains multiple paths + _comp_expand_glob files '$i' + if ((${#files[@]})); then + for f in "${files[@]}"; do + if [[ -r $f && ! -d $f ]]; then + config+=("$f") + included+=("$f") + fi + done + fi + done done } # _included_ssh_config_files()