bash - bash 是否在 ${var+...} 内错误地执行“$@”扩展?
问题描述
我目前得到 3 个 shell 的 2 个意见:
$ bash -c 'set bar; set foo${1+ "$@"}; echo "$# $*"'
1 foobar
$ ash -c 'set bar; set foo${1+ "$@"}; echo "$# $*"'
2 foo bar
$ dash -c 'set bar; set foo${1+ "$@"}; echo "$# $*"'
2 foo bar
或者我是否忽略了一些将我的示例呈现为实现定义的行为的 POSIX 定义?
请注意,似乎只有“$@”会触发差异。以下对所有 3 个 shell 的工作方式相同:
$ bash -c 'set bar; set foo${1+ $*}; echo "$# $*"'
2 foo bar
$ ash -c 'set bar; set foo${1+ $*}; echo "$# $*"'
2 foo bar
$ dash -c 'set bar; set foo${1+ $*}; echo "$# $*"'
2 foo bar
不幸的是,如果参数应该包含空格,则 $* 与 "$@" 并不完全相同。
顺便说一句,我使用的是 Bash 版本 4.4.12(1)-release。
解决方案
虽然这看起来确实是一个错误,但我之前遇到过一些带有“... $@”的奇怪边缘情况,这符合预期的行为,至少从历史上看是这样。" $@"
(带有悬挂空白)是未定义的行为,因为您基本上要求将$@
数组的所有成员视为 shell 解析器的 args加上一个空白字符。你可能有点难以理解,而且你所说的一些事情具有误导性,所以我想我会提供更多信息和提示以实现更好的行为。
您使用 "$@" 并尝试将其与 "$*" 互换的方式会给您带来问题。与其预期用途相匹配的行为$*
之间存在显着差异。$@
如果你使用$@
,那是因为你想做这样的事情:
wrapper_fxn() {
wrapped_cmd "$@"
}
当您将 $@ 括在引号中(以及任何其他数组)时,bash 会评估它,就好像数组的每个参数/成员首先用双引号括起来一样。但是,这涉及到更多的魔法,因为它实际上并没有将其包装在双引号中,而是删除了双引号,但表示在稍后的步骤中更改解析行为。
存在的特殊行为的原因"$@"
是帮助处理令人沮丧quoting
和argv
干扰的问题。
所以,这样想它们:
- $@ : 多个 args / 用于传播 args,同时保留空格的引用
- $* : 单个 arg / 用于将数组中的所有字符串连接为单个 arg
我的建议:不要这样做"$@ "
;这是未定义的行为。只要你引用 like "$@"
,你就在尝试进行参数扩展,并添加另一个参数或参数数组,就像这样:
# Making sure to have quotes around each new arg
somecmd "$newFirstArg" "$@" "${additionalArray[@]}" "$newLastArg"
...它将更好地传达意图,并且几乎不会产生意外行为。
更深入
话虽如此,“$@”的奇怪边缘行为在您使用它时必须这样做:"... $@"
,就像“$@”一样。Bash 将合并数组中的一项,具体取决于...
带有额外字符的位置。
$@
当您在引用语句的右侧或左侧添加任何内容时,例如 "extra stuff $@"
or "$@ extra stuff"
,bash 所做的只是将 分别添加extra stuff
到数组的第一个或最后一个成员上。例外情况是,如果双引号语句中有另一个数组,可能$@
像这样重复:"$@ $@"
. 它实际上会将第一个数组的最后一项与最后一个数组的第一项合并。所以,如果$@
有 3 个成员,final argv[]
of"$@ $@"
将有 5 个 args,而不是 6 个。
这是一个实用功能,可帮助您了解该行为:
# example function
print-args ()
{
local i=0;
for arg in "$@";
do
printf "[${i}]:%s\n" "\"$arg\"";
let i++;
done
}
# good example arg-set covering many of the important edge cases
set "one \"one" two three
# One case, modify it to see the various permutations of the edge cases
print-args " $@ $@ "
#>[0]:" one "one"
#>[1]:"two"
#>[2]:"three one "one"
#>[3]:"two"
#>[4]:"three "
推荐阅读
- python - 将多个列值合并为一列作为python pandas中的列表
- sql - 将其中两列与 sum 函数进行比较
- swift - Swift - 有没有办法在不调用对象的情况下在对象上运行方法?(自己?)
- r - 在 R 中将空值转换为 NULL - 处理日期列
- javascript - 如何正确链接 Vuex 操作,并在调用之间正确改变状态?
- python - ValueError:Series 的真值不明确。在尝试将函数与 pandas df 一起使用时使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()
- python - 无法从放置在 Google Drive 上并使用 google colab 的文件中解压缩和读取数据
- python - 由于 Apache Superset 中的 JSON 解码错误,无法加载仪表板列表
- mongodb - Mongoose 错误:传入的参数必须是 12 个字节的单个字符串或 24 个十六进制字符的字符串
- r - 在 Databricks 中使用 sparklyr 收集表