Skip to content

Commit abc394a

Browse files
committed
fix(_comp_dequote): set the literal value to REPLY as a fallback
It is more useful to set the literal value of $1 to REPLY even when $1 is an unsafe word. When the caller wants to use the result only when REPLY is a safe string and suceceds without failglob, the caller can reference the exit status $?. When the caller wants to use any string, it is more useful if REPLY contains a fallback value. This patch changes the behavior so that REPLY is set to be the literal value of $1 even when an unsafe value is specified to $1. We also change the exit status to be 0 only when at least one word is generated by a safe string. all callers of _comp_dequote, it is more useful
1 parent 64f8133 commit abc394a

File tree

7 files changed

+35
-24
lines changed

7 files changed

+35
-24
lines changed

bash_completion

+22-10
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ _comp_dequote__initialize()
188188
_comp_dequote__initialize
189189

190190
# This function expands a word using `eval` in a safe way. This function can
191-
# be typically used to get the expanded value of `${word[i]}` as
192-
# `_comp_dequote "${word[i]}"`. When the word contains unquoted shell special
193-
# characters, command substitutions, and other unsafe strings, the function
194-
# call fails before applying `eval`. Otherwise, `eval` is applied to the
195-
# string to generate the result.
191+
# be typically used to get the expanded value of `${word[i]}` as `_comp_dequote
192+
# "${word[i]}"`. When the word contains unquoted shell special characters,
193+
# command substitutions, and other unsafe strings, the function call fails
194+
# before applying `eval` and REPLY is set to be the literal string. Otherwise,
195+
# `eval` is applied to the string to generate the result.
196196
#
197197
# @param $1 String to be expanded. A safe word consists of the following
198198
# sequence of substrings:
@@ -207,7 +207,12 @@ _comp_dequote__initialize
207207
# quotations, parameter expansions are allowed.
208208
#
209209
# @var[out] REPLY Array that contains the expanded results. Multiple words or
210-
# no words may be generated through pathname expansions.
210+
# no words may be generated through pathname expansions. If
211+
# $1 is not a safe word, REPLY contains the literal value of
212+
# $1.
213+
#
214+
# @return 0 if $1 is a safe word and the expansion result contains one word at
215+
# least, or 1 otherwise.
211216
#
212217
# Note: This function allows parameter expansions as safe strings, which might
213218
# cause unexpected results:
@@ -235,8 +240,15 @@ _comp_dequote__initialize
235240
_comp_dequote()
236241
{
237242
REPLY=() # fallback value for unsafe word and failglob
238-
[[ $1 =~ $_comp_dequote__regex_safe_word ]] || return 1
239-
eval "REPLY=($1)" 2>/dev/null # may produce failglob
243+
if [[ ${1-} =~ $_comp_dequote__regex_safe_word ]]; then
244+
eval "REPLY=($1)" 2>/dev/null # may produce failglob
245+
((${#REPLY[@]} > 0))
246+
return "$?"
247+
else
248+
# shellcheck disable=SC2178
249+
REPLY=${1-}
250+
return 1
251+
fi
240252
}
241253

242254
# Unset the given variables across a scope boundary. Useful for unshadowing
@@ -1559,7 +1571,7 @@ _comp_compgen_help__get_help_lines()
15591571
--) shift 1 ;&
15601572
*)
15611573
local REPLY
1562-
_comp_dequote "${comp_args[0]-}" || REPLY=${comp_args[0]-}
1574+
_comp_dequote "${comp_args[0]-}"
15631575
help_cmd=("${REPLY:-false}" "$@")
15641576
;;
15651577
esac
@@ -2855,7 +2867,7 @@ _comp_command_offset()
28552867
if ((COMP_CWORD == 0)); then
28562868
_comp_compgen_commands
28572869
else
2858-
_comp_dequote "${COMP_WORDS[0]}" || REPLY=${COMP_WORDS[0]}
2870+
_comp_dequote "${COMP_WORDS[0]}"
28592871
local cmd=${REPLY-} compcmd=${REPLY-}
28602872
local cspec=$(complete -p -- "$cmd" 2>/dev/null)
28612873

completions/java

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ _comp_cmd_java__packages()
114114
local -a sourcepaths=("${REPLY[@]}")
115115

116116
local REPLY
117-
_comp_dequote "$cur" || REPLY=$cur
117+
_comp_dequote "$cur"
118118
local cur_val=${REPLY-}
119119

120120
# convert package syntax to path syntax

completions/make

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ _comp_cmd_make()
121121
# Expand tilde expansion
122122
local REPLY
123123
_comp_dequote "${words[i + 1]-}" &&
124-
[[ -d ${REPLY-} ]] &&
124+
[[ -d $REPLY ]] &&
125125
makef_dir=(-C "$REPLY")
126126
break
127127
fi
@@ -134,7 +134,7 @@ _comp_cmd_make()
134134
# Expand tilde expansion
135135
local REPLY
136136
_comp_dequote "${words[i + 1]-}" &&
137-
[[ -f ${REPLY-} ]] &&
137+
[[ -f $REPLY ]] &&
138138
makef=(-f "$REPLY")
139139
break
140140
fi

completions/mutt

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ _comp_cmd_mutt__get_muttrc()
3232
shift
3333
done
3434

35-
if [[ ! $REPLY ]]; then
35+
if [[ ! ${REPLY-} ]]; then
3636
if [[ -f ~/.${muttcmd}rc ]]; then
3737
REPLY=\~/.${muttcmd}rc
3838
elif [[ -f ~/.${muttcmd}/${muttcmd}rc ]]; then
@@ -52,7 +52,7 @@ _comp_cmd_mutt__get_conffiles()
5252
local file
5353
for file; do
5454
_comp_dequote "$file"
55-
_comp_cmd_mutt__get_conffiles__visit "$REPLY"
55+
_comp_cmd_mutt__get_conffiles__visit "${REPLY-}"
5656
done
5757
((${#conffiles[@]})) || return 1
5858
REPLY=("${conffiles[@]}")

completions/pkgutil

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ _comp_cmd_pkgutil()
3333
catalog_files=("$REPLY")
3434
elif [[ ${words[i]} == --config ]]; then
3535
local REPLY
36-
_comp_dequote "${words[i + 1]}"
37-
[[ ${REPLY-} ]] && configuration_files=("$REPLY")
36+
_comp_dequote "${words[i + 1]}" && configuration_files=("$REPLY")
3837
elif [[ ${words[i]} == -@([iurdacUS]|-install|-upgrade|-remove|-download|-available|-compare|-catalog|-stream) ]]; then
3938
command="${words[i]}"
4039
fi

completions/ssh

+1-1
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ _comp_xfunc_scp_compgen_local_files()
577577
fi
578578

579579
local REPLY
580-
_comp_dequote "$cur" || REPLY=$cur
580+
_comp_dequote "$cur"
581581
local cur_val=${REPLY-}
582582

583583
local files

test/t/unit/test_unit_dequote.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def test_2_str(self, bash, functions):
2525
assert output.strip() == "<abc>"
2626

2727
def test_3_null(self, bash, functions):
28-
output = assert_bash_exec(bash, "__tester ''", want_output=True)
28+
output = assert_bash_exec(bash, "! __tester ''", want_output=True)
2929
assert output.strip() == ""
3030

3131
def test_4_empty(self, bash, functions):
@@ -108,25 +108,25 @@ def test_unsafe_1(self, bash, functions):
108108
output = assert_bash_exec(
109109
bash, "! __tester '$(echo hello >&2)'", want_output=True
110110
)
111-
assert output.strip() == ""
111+
assert output.strip() == "<$(echo hello >&2)>"
112112

113113
def test_unsafe_2(self, bash, functions):
114114
output = assert_bash_exec(
115115
bash, "! __tester '|echo hello >&2'", want_output=True
116116
)
117-
assert output.strip() == ""
117+
assert output.strip() == "<|echo hello >&2>"
118118

119119
def test_unsafe_3(self, bash, functions):
120120
output = assert_bash_exec(
121121
bash, "! __tester '>| important_file.txt'", want_output=True
122122
)
123-
assert output.strip() == ""
123+
assert output.strip() == "<>| important_file.txt>"
124124

125125
def test_unsafe_4(self, bash, functions):
126126
output = assert_bash_exec(
127127
bash, "! __tester '`echo hello >&2`'", want_output=True
128128
)
129-
assert output.strip() == ""
129+
assert output.strip() == "<`echo hello >&2`>"
130130

131131
def test_glob_default(self, bash, functions):
132132
with bash_env_saved(bash) as bash_env:
@@ -160,6 +160,6 @@ def test_glob_nullglob(self, bash, functions):
160160
bash_env.shopt("failglob", False)
161161
bash_env.shopt("nullglob", True)
162162
output = assert_bash_exec(
163-
bash, "__tester 'non-existent-*.txt'", want_output=True
163+
bash, "! __tester 'non-existent-*.txt'", want_output=True
164164
)
165165
assert output.strip() == ""

0 commit comments

Comments
 (0)