Skip to content

Commit d8ea18b

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.
1 parent badc247 commit d8ea18b

File tree

7 files changed

+35
-24
lines changed

7 files changed

+35
-24
lines changed

bash_completion

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,11 @@ _comp_dequote__initialize()
190190
_comp_dequote__initialize
191191

192192
# This function expands a word using `eval` in a safe way. This function can
193-
# be typically used to get the expanded value of `${word[i]}` as
194-
# `_comp_dequote "${word[i]}"`. When the word contains unquoted shell special
195-
# characters, command substitutions, and other unsafe strings, the function
196-
# call fails before applying `eval`. Otherwise, `eval` is applied to the
197-
# string to generate the result.
193+
# be typically used to get the expanded value of `${word[i]}` as `_comp_dequote
194+
# "${word[i]}"`. When the word contains unquoted shell special characters,
195+
# command substitutions, and other unsafe strings, the function call fails
196+
# before applying `eval` and REPLY is set to be the literal string. Otherwise,
197+
# `eval` is applied to the string to generate the result.
198198
#
199199
# @param $1 String to be expanded. A safe word consists of the following
200200
# sequence of substrings:
@@ -209,7 +209,12 @@ _comp_dequote__initialize
209209
# quotations, parameter expansions are allowed.
210210
#
211211
# @var[out] REPLY Array that contains the expanded results. Multiple words or
212-
# no words may be generated through pathname expansions.
212+
# no words may be generated through pathname expansions. If
213+
# $1 is not a safe word, REPLY contains the literal value of
214+
# $1.
215+
#
216+
# @return 0 if $1 is a safe word and the expansion result contains one word at
217+
# least, or 1 otherwise.
213218
#
214219
# Note: This function allows parameter expansions as safe strings, which might
215220
# cause unexpected results:
@@ -237,8 +242,15 @@ _comp_dequote__initialize
237242
_comp_dequote()
238243
{
239244
REPLY=() # fallback value for unsafe word and failglob
240-
[[ $1 =~ $_comp_dequote__regex_safe_word ]] || return 1
241-
eval "REPLY=($1)" 2>/dev/null # may produce failglob
245+
if [[ ${1-} =~ $_comp_dequote__regex_safe_word ]]; then
246+
eval "REPLY=($1)" 2>/dev/null # may produce failglob
247+
((${#REPLY[@]} > 0))
248+
return "$?"
249+
else
250+
# shellcheck disable=SC2178
251+
REPLY=${1-}
252+
return 1
253+
fi
242254
}
243255

244256
# Unset the given variables across a scope boundary. Useful for unshadowing
@@ -1625,7 +1637,7 @@ _comp_compgen_help__get_help_lines()
16251637
--) shift 1 ;&
16261638
*)
16271639
local REPLY
1628-
_comp_dequote "${comp_args[0]-}" || REPLY=${comp_args[0]-}
1640+
_comp_dequote "${comp_args[0]-}"
16291641
help_cmd=("${REPLY:-false}" "$@")
16301642
;;
16311643
esac
@@ -2921,7 +2933,7 @@ _comp_command_offset()
29212933
if ((COMP_CWORD == 0)); then
29222934
_comp_compgen_commands
29232935
else
2924-
_comp_dequote "${COMP_WORDS[0]}" || REPLY=${COMP_WORDS[0]}
2936+
_comp_dequote "${COMP_WORDS[0]}"
29252937
local cmd=${REPLY-} compcmd=${REPLY-}
29262938
local cspec=$(complete -p -- "$cmd" 2>/dev/null)
29272939

completions/java

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 2 deletions
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ _comp_xfunc_scp_compgen_local_files()
586586
fi
587587

588588
local REPLY
589-
_comp_dequote "$cur" || REPLY=$cur
589+
_comp_dequote "$cur"
590590
local cur_val=${REPLY-}
591591

592592
local files

test/t/unit/test_unit_dequote.py

Lines changed: 6 additions & 6 deletions
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)