@@ -461,6 +461,41 @@ _comp_cmd_sftp()
461461# things we want to backslash escape in scp paths
462462_comp_cmd_scp__path_esc=' [][(){}<>"' " '" ' ,:;^&!$=?`\\|[:space:]]'
463463
464+ # Escape shell special characters in filenames by backslash. This also
465+ # suffixes a space or a slash based on the file type.
466+ #
467+ # Note: With a non-empty prefix ($1 of _comp_xfunc_scp_compgen_local_files),
468+ # Bash will not recognize any filenames, so we need to perform the proper
469+ # quoting manually. We also need to manually suffix a space or a slash based
470+ # on the file type because "-o nospace" is specified. One might think of using
471+ # "compopt +o nospace" instead, but it would suffix a space to directory names
472+ # unexpectedly.
473+ #
474+ # @param $1 dirs_only - If a non-empty value is specified, only directory names
475+ # are selected.
476+ # @param $2 escape_replacement - If a non-empty value is specified, special
477+ # characters are replaced with the specified value (instead of the default
478+ # '\\&').
479+ # @stdin - List of filenames in the "ls -1F" format, where filenames are
480+ # separated by newlines, and characters /=@|* are suffixed based on the types
481+ # of the files.
482+ _comp_cmd_scp__escape_path ()
483+ {
484+ local dirs_only=$1 escape_replacement=${2:- ' \\&' }
485+ if [[ $dirs_only ]]; then
486+ # escape problematic characters; remove non-dirs
487+ command sed \
488+ -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $escape_replacement " ' /g' \
489+ -e ' /[^/]$/d'
490+ else
491+ # escape problematic characters; remove executables, aliases, pipes
492+ # and sockets; add space at end of file names
493+ command sed \
494+ -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $escape_replacement " ' /g' \
495+ -e ' s/[*@]$//g' -e ' s/\\[|=]$//g' -e ' s/[^/]$/& /g'
496+ fi
497+ }
498+
464499# Complete remote files with ssh. Returns paths escaped with three backslashes
465500# (unless -l option is provided).
466501# Options:
@@ -505,19 +540,9 @@ _comp_xfunc_scp_compgen_remote_files()
505540 fi
506541
507542 local _files
508- if [[ $_dirs_only ]]; then
509- # escape problematic characters; remove non-dirs
510- _files=$( ssh -o ' Batchmode yes' " $_userhost " \
511- command ls -aF1dL " $_path *" 2> /dev/null |
512- command sed -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $_escape_replacement " ' /g' -e ' /[^/]$/d' )
513- else
514- # escape problematic characters; remove executables, aliases, pipes
515- # and sockets; add space at end of file names
516- _files=$( ssh -o ' Batchmode yes' " $_userhost " \
517- command ls -aF1dL " $_path *" 2> /dev/null |
518- command sed -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $_escape_replacement " ' /g' \
519- -e ' s/[*@]$//g' -e ' s/\\[|=]$//g' -e ' s/[^/]$/& /g' )
520- fi
543+ _files=$( ssh -o ' Batchmode yes' " $_userhost " \
544+ command ls -aF1dL " $_path *" 2> /dev/null |
545+ _comp_cmd_scp__escape_path " $_dirs_only " " $_escape_replacement " )
521546 _comp_compgen -R split -l -- " $_files "
522547}
523548
@@ -542,19 +567,10 @@ _comp_xfunc_scp_compgen_local_files()
542567
543568 local files
544569 _comp_expand_glob files ' "$cur"*' || return 0
545- if [[ $_dirsonly ]]; then
546- _comp_compgen -RU files split -l ${1: +-P " $1 " } -- " $(
547- command ls -aF1dL " ${files[@]} " 2> /dev/null |
548- command sed -e " s/$_comp_cmd_scp__path_esc /\\\\ &/g" \
549- -e ' /[^/]$/d'
550- ) "
551- else
552- _comp_compgen -RU files split -l ${1: +-P " $1 " } -- " $(
553- command ls -aF1dL " ${files[@]} " 2> /dev/null |
554- command sed -e " s/$_comp_cmd_scp__path_esc /\\\\ &/g" \
555- -e ' s/[*@]$//g' -e ' s/\\[|=]$//g' -e ' s/[^/]$/& /g'
556- ) "
557- fi
570+ _comp_compgen -RU files split -l ${1: +-P " $1 " } -- " $(
571+ command ls -aF1dL " ${files[@]} " 2> /dev/null |
572+ _comp_cmd_scp__escape_path " $_dirsonly "
573+ ) "
558574}
559575
560576# @deprecated 2.12
0 commit comments