diff --git a/completions/ssh b/completions/ssh index 3f764d9b8f6..f6896c9f0f6 100644 --- a/completions/ssh +++ b/completions/ssh @@ -374,6 +374,7 @@ _sftp() local ipvx + case $prev in -*[BDlPRs]) return @@ -429,13 +430,25 @@ _sftp() # shellcheck disable=SC2089 _comp_cmd_scp__path_esc='[][(){}<>"'"'"',:;^&!$=?`\\|[:space:]]' -# Complete remote files with ssh. If the first arg is -d, complete on dirs -# only. Returns paths escaped with three backslashes. +# Complete remote files with ssh. If the arg is -d, complete on dirs +# only. Returns paths escaped with three backslashes. +# Pass argument as "-p portnumber" for non-default ssh connection port. # shellcheck disable=SC2120 _comp_xfunc_ssh_scp_remote_files() { local IFS=$'\n' - + + local sshoption + local dirsonly=false + local i + for i in "$@"; do + if [[ ${i-} == -d ]]; then + dirsonly=true + elif [[ ${i:0:2} == -p ]]; then + sshoption=$1 + fi + done + # remove backslash escape from the first colon cur=${cur/\\:/:} @@ -448,21 +461,21 @@ _comp_xfunc_ssh_scp_remote_files() # default to home dir of specified user on remote host if [[ ! $path ]]; then - path=$(ssh -o 'Batchmode yes' "$userhost" pwd 2>/dev/null) + path=$(ssh $sshoption -o 'Batchmode yes' "$userhost" pwd 2>/dev/null) fi local files - if [[ ${1-} == -d ]]; then + if $dirsonly; then # escape problematic characters; remove non-dirs # shellcheck disable=SC2090 - files=$(ssh -o 'Batchmode yes' "$userhost" \ + files=$(ssh $sshoption -o 'Batchmode yes' "$userhost" \ command ls -aF1dL "$path*" 2>/dev/null | command sed -e 's/'"$_comp_cmd_scp__path_esc"'/\\\\\\&/g' -e '/[^\/]$/d') else # escape problematic characters; remove executables, aliases, pipes # and sockets; add space at end of file names # shellcheck disable=SC2090 - files=$(ssh -o 'Batchmode yes' "$userhost" \ + files=$(ssh $sshoption -o 'Batchmode yes' "$userhost" \ command ls -aF1dL "$path*" 2>/dev/null | command sed -e 's/'"$_comp_cmd_scp__path_esc"'/\\\\\\&/g' -e 's/[*@|=]$//g' \ -e 's/[^\/]$/& /g') @@ -515,6 +528,31 @@ _scp() } local ipvx + + # Parse Port number from command + local sshport="" + local sshoption="" + local i + for ((i = 0; i < ${#words[@]}; i++)); do + if [[ ${words[i]} =~ -[a-zA-Z0-9]*P[0-9]*$ ]]; then + if [[ ${words[i]: -1} == P ]]; then + ((i+=1)) + [[ ${words[i]} =~ ^[0-9]+$ ]] && sshport=${words[i]} + else + sshport=$(echo ${words[i]} | command sed -n 's/-.*P\([0-9]\{1,\}\)/\1/p') + fi + elif [[ ${words[i]} =~ -[a-zA-Z0-9]*o$ ]]; then + if [[ ${words[i+1],,} == port ]]; then + ((i+=3)) + [[ ${words[i]} =~ ^[0-9]+$ ]] && sshport=${words[i]} + fi + elif [[ ${words[i]} =~ -[a-zA-Z0-9]*o[pP][oO][rR][tT]$ ]]; then + ((i+=2)) + [[ ${words[i]} =~ ^[0-9]+$ ]] && sshport=${words[i]} + fi + done + + [[ ${sshport// } ]] && sshoption="-p $sshport" case $prev in -*c) @@ -561,7 +599,7 @@ _scp() case $cur in !(*:*)/* | [.~]*) ;; # looks like a path *:*) - _comp_xfunc_ssh_scp_remote_files + _comp_xfunc_ssh_scp_remote_files "$sshoption" return ;; esac