@@ -461,6 +461,42 @@ _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+ # Options:
475+ # -d Only directory names 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
481+ # types 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 ' /[^/]$/d' \
489+ -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $escape_replacement " ' /g'
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/[*@|=]$//g' \
495+ -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $escape_replacement " ' /g' \
496+ -e ' s/[^/]$/& /g'
497+ fi
498+ }
499+
464500# Complete remote files with ssh. Returns paths escaped with three backslashes
465501# (unless -l option is provided).
466502# Options:
@@ -505,20 +541,9 @@ _comp_xfunc_scp_compgen_remote_files()
505541 fi
506542
507543 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/[*@|=]$//g' \
519- -e ' s/' " $_comp_cmd_scp__path_esc " ' /' " $_escape_replacement " ' /g' \
520- -e ' s/[^/]$/& /g' )
521- fi
544+ _files=$( ssh -o ' Batchmode yes' " $_userhost " \
545+ command ls -aF1dL " $_path *" 2> /dev/null |
546+ _comp_cmd_scp__escape_path " $_dirs_only " " $_escape_replacement " )
522547 _comp_compgen -R split -l -- " $_files "
523548}
524549
@@ -543,20 +568,10 @@ _comp_xfunc_scp_compgen_local_files()
543568
544569 local files
545570 _comp_expand_glob files ' "$cur"*' || return 0
546- if [[ $_dirs_only ]]; then
547- _comp_compgen -RU files split -l ${1: +-P " $1 " } -- " $(
548- command ls -aF1dL " ${files[@]} " 2> /dev/null |
549- command sed -e " s/$_comp_cmd_scp__path_esc /\\\\ &/g" \
550- -e ' /[^/]$/d'
551- ) "
552- else
553- _comp_compgen -RU files split -l ${1: +-P " $1 " } -- " $(
554- command ls -aF1dL " ${files[@]} " 2> /dev/null |
555- command sed -e ' s/[*@|=]$//g' \
556- -e " s/$_comp_cmd_scp__path_esc /\\\\ &/g" \
557- -e ' s/[^/]$/& /g'
558- ) "
559- fi
571+ _comp_compgen -RU files split -l ${1: +-P " $1 " } -- " $(
572+ command ls -aF1dL " ${files[@]} " 2> /dev/null |
573+ _comp_cmd_scp__escape_path " $_dirs_only "
574+ ) "
560575}
561576
562577# @deprecated 2.12
0 commit comments