Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions bash_completion
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,11 @@ _comp_dequote__initialize()
_comp_dequote__initialize

# This function expands a word using `eval` in a safe way. This function can
# be typically used to get the expanded value of `${word[i]}` as
# `_comp_dequote "${word[i]}"`. When the word contains unquoted shell special
# characters, command substitutions, and other unsafe strings, the function
# call fails before applying `eval`. Otherwise, `eval` is applied to the
# string to generate the result.
# be typically used to get the expanded value of `${word[i]}` as `_comp_dequote
# "${word[i]}"`. When the word contains unquoted shell special characters,
# command substitutions, and other unsafe strings, the function call fails
# before applying `eval` and REPLY is set to be the literal string. Otherwise,
# `eval` is applied to the string to generate the result.
#
# @param $1 String to be expanded. A safe word consists of the following
# sequence of substrings:
Expand All @@ -209,7 +209,12 @@ _comp_dequote__initialize
# quotations, parameter expansions are allowed.
#
# @var[out] REPLY Array that contains the expanded results. Multiple words or
# no words may be generated through pathname expansions.
# no words may be generated through pathname expansions. If
# $1 is not a safe word, REPLY contains the literal value of
# $1.
#
# @return 0 if $1 is a safe word and the expansion result contains one word at
# least, or 1 otherwise.
#
# Note: This function allows parameter expansions as safe strings, which might
# cause unexpected results:
Expand All @@ -236,9 +241,15 @@ _comp_dequote__initialize
# @since 2.12
_comp_dequote()
{
REPLY=() # fallback value for unsafe word and failglob
[[ $1 =~ $_comp_dequote__regex_safe_word ]] || return 1
eval "REPLY=($1)" 2>/dev/null # may produce failglob
if [[ ${1-} =~ $_comp_dequote__regex_safe_word ]]; then
REPLY=() # fallback value for failglob
eval "REPLY=($1)" 2>/dev/null # may produce failglob
((${#REPLY[@]} > 0))
return "$?"
else
REPLY=("${1-}")
return 1
fi
}

# Unset the given variables across a scope boundary. Useful for unshadowing
Expand Down Expand Up @@ -1627,7 +1638,7 @@ _comp_compgen_help__get_help_lines()
--) shift 1 ;&
*)
local REPLY
_comp_dequote "${comp_args[0]-}" || REPLY=${comp_args[0]-}
_comp_dequote "${comp_args[0]-}"
help_cmd=("${REPLY:-false}" "$@")
;;
esac
Expand Down Expand Up @@ -2923,7 +2934,7 @@ _comp_command_offset()
if ((COMP_CWORD == 0)); then
_comp_compgen_commands
else
_comp_dequote "${COMP_WORDS[0]}" || REPLY=${COMP_WORDS[0]}
_comp_dequote "${COMP_WORDS[0]}"
local cmd=${REPLY-} compcmd=${REPLY-}
local cspec=$(complete -p -- "$cmd" 2>/dev/null)

Expand Down
2 changes: 1 addition & 1 deletion completions/java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ _comp_cmd_java__packages()
local -a sourcepaths=("${REPLY[@]}")

local REPLY
_comp_dequote "$cur" || REPLY=$cur
_comp_dequote "$cur"
local cur_val=${REPLY-}

# convert package syntax to path syntax
Expand Down
4 changes: 2 additions & 2 deletions completions/make
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ _comp_cmd_make()
# Expand tilde expansion
local REPLY
_comp_dequote "${words[i + 1]-}" &&
[[ -d ${REPLY-} ]] &&
[[ -d $REPLY ]] &&
makef_dir=(-C "$REPLY")
break
fi
Expand All @@ -134,7 +134,7 @@ _comp_cmd_make()
# Expand tilde expansion
local REPLY
_comp_dequote "${words[i + 1]-}" &&
[[ -f ${REPLY-} ]] &&
[[ -f $REPLY ]] &&
makef=(-f "$REPLY")
break
fi
Expand Down
4 changes: 2 additions & 2 deletions completions/mutt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ _comp_cmd_mutt__get_muttrc()
shift
done

if [[ ! $REPLY ]]; then
if [[ ! ${REPLY-} ]]; then
if [[ -f ~/.${muttcmd}rc ]]; then
REPLY=\~/.${muttcmd}rc
elif [[ -f ~/.${muttcmd}/${muttcmd}rc ]]; then
Expand All @@ -52,7 +52,7 @@ _comp_cmd_mutt__get_conffiles()
local file
for file; do
_comp_dequote "$file"
_comp_cmd_mutt__get_conffiles__visit "$REPLY"
_comp_cmd_mutt__get_conffiles__visit "${REPLY-}"
done
((${#conffiles[@]})) || return 1
REPLY=("${conffiles[@]}")
Expand Down
3 changes: 1 addition & 2 deletions completions/pkgutil
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ _comp_cmd_pkgutil()
catalog_files=("$REPLY")
elif [[ ${words[i]} == --config ]]; then
local REPLY
_comp_dequote "${words[i + 1]}"
[[ ${REPLY-} ]] && configuration_files=("$REPLY")
_comp_dequote "${words[i + 1]}" && configuration_files=("$REPLY")
elif [[ ${words[i]} == -@([iurdacUS]|-install|-upgrade|-remove|-download|-available|-compare|-catalog|-stream) ]]; then
command="${words[i]}"
fi
Expand Down
2 changes: 1 addition & 1 deletion completions/ssh
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ _comp_xfunc_scp_compgen_local_files()
fi

local REPLY
_comp_dequote "$cur" || REPLY=$cur
_comp_dequote "$cur"
local cur_val=${REPLY-}

local files
Expand Down
12 changes: 6 additions & 6 deletions test/t/unit/test_unit_dequote.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_2_str(self, bash, functions):
assert output.strip() == "<abc>"

def test_3_null(self, bash, functions):
output = assert_bash_exec(bash, "__tester ''", want_output=True)
output = assert_bash_exec(bash, "! __tester ''", want_output=True)
assert output.strip() == ""

def test_4_empty(self, bash, functions):
Expand Down Expand Up @@ -108,25 +108,25 @@ def test_unsafe_1(self, bash, functions):
output = assert_bash_exec(
bash, "! __tester '$(echo hello >&2)'", want_output=True
)
assert output.strip() == ""
assert output.strip() == "<$(echo hello >&2)>"

def test_unsafe_2(self, bash, functions):
output = assert_bash_exec(
bash, "! __tester '|echo hello >&2'", want_output=True
)
assert output.strip() == ""
assert output.strip() == "<|echo hello >&2>"

def test_unsafe_3(self, bash, functions):
output = assert_bash_exec(
bash, "! __tester '>| important_file.txt'", want_output=True
)
assert output.strip() == ""
assert output.strip() == "<>| important_file.txt>"

def test_unsafe_4(self, bash, functions):
output = assert_bash_exec(
bash, "! __tester '`echo hello >&2`'", want_output=True
)
assert output.strip() == ""
assert output.strip() == "<`echo hello >&2`>"

def test_glob_default(self, bash, functions):
with bash_env_saved(bash) as bash_env:
Expand Down Expand Up @@ -160,6 +160,6 @@ def test_glob_nullglob(self, bash, functions):
bash_env.shopt("failglob", False)
bash_env.shopt("nullglob", True)
output = assert_bash_exec(
bash, "__tester 'non-existent-*.txt'", want_output=True
bash, "! __tester 'non-existent-*.txt'", want_output=True
)
assert output.strip() == ""