使用$ @变量的奇怪行为

时间:2012-06-30 00:51:01

标签: shell unix variables

据我理解并阅读,$@变成“arg1”“arg2”“arg3”。
但在引用的某些情况下似乎有一些奇怪的行为

测试1,$ @

$ function somefunc { sh -c "echo $@"; }
$ somefunc 1 2 3
> + somefunc 1 2 3
> + sh -c 'echo 1' 2 3
> 1

预期的输出是1 2 3,我得到的输出是1.现在我看到,由于某种原因,它似乎只传递echo 1作为命令,但为什么"echo "1" "2" "3""变成它?我可能已经预料到echo ,因为“之前的回声可能会在1之前被”关闭
测试2,$ *

$ function somefunc { sh -c "echo $*"; }
$ somefunc 1 2 3
> + somefunc 1 2 3
> + sh -c 'echo 1 2 3'
> 1 2 3

这非常明显且有效,只是为了确保。在所有$*通过1 2 3之后,而不是"1" "2" "3"
测试3,$ @和$ *

$ function somefunc { sh -c "echo $@ $*"; }
$ somefunc 1 2 3
> + somefunc 1 2 3
> + sh -c 'echo 1 2 3 1 2 3'
> 1 2 3 1 2 3

这似乎又奇怪了。但我不知道"echo "1" "2" "3" 1 2 3"如何变成'echo 1 2 3 1 2 3'并且不遵循只有"echo $@"所做的“模式”。

测试4,$ @和字符串

$ function somefunc { sh -c "echo $@ hi"; }
$ somefunc 1 2 3
> + somefunc 1 2 3
> + sh -c 'echo 1' 2 '3 hi'
> 1

这再次遵循"echo $@"的模式,甚至认为,正如我所看到的,它与"echo $@ $*"几乎相同,因为$*毕竟变成了一个字符串。 /> 让我感到困惑的是它变成'echo 1' 2 '3 hi',第一个测试会建议'echo 1' 2 3 hi(没有'围绕3 hi

测试5,$ @和$ var

$ var="hi"
> + var=hi
$ function somefunc { sh -c "echo $@ $var"; }
$ somefunc 1 2 3
> + somefunc 1 2 3
> + sh -c 'echo 1 2 3 hi'
> 1 2 3 hi

这再次起作用。所以$@似乎有效,如果另一个变量跟随它。

使用su user -cbash -c代替sh -c也可以进行测试,所以我想也会执行下一个给定参数的所有其他命令。

我现在似乎已经从中获得了某种行为,
但我仍然不明白这种行为 我在这里缺少什么?

3 个答案:

答案 0 :(得分:2)

sh language spec可以说$@

从1开始扩展到位置参数。当扩展发生在双引号内,并且执行字段拆分(参见字段拆分)时,每个位置参数应作为单独的字段扩展,并规定第一个参数的扩展仍应与开头部分连接原始单词(假设扩展参数嵌入在单词中),最后一个参数的扩展仍然与原始单词的最后部分连接。如果没有位置参数,“@”的扩展将产生零字段,即使“@”是双引号。

这意味着位置参数为"echo $@ $*"12的字符串3应扩展为"echo 1" "2" "3 1 2 3",以便您的测试3应该输出字符串1。 bash错误地将字符串扩展为"echo 1 2 3 1 2 3"并输出1 2 3 1 2 3这一事实表明bash中存在错误。

处理这个(又一个)sh语法规则的奇怪之处的常用技巧是当它是一个不同的单词时,只在双引号中使用$ @。换句话说,可以写"$@",但不要将$@放在双引号中,除非它是双引号内的唯一内容。

答案 1 :(得分:1)

使用@BrianSwift的提示,一切都非常有意义,除了 Test3 (这里,我们得到三个参数的情况,第一个参数的前缀是'echo ',第三个后缀为' $*'。相反,结果是一个参数。)

但这可能是因为$@$*都是“特殊”变量,而shell中存在特殊代码。我假设$*的存在只是覆盖@BrianSwift注意到的特殊行为,因为$*稍后会被评估。

尝试交换订单:somefunc() { sh -x "echo $* $@"; }。您将再次获得split-with-prefix-and-suffix行为,这似乎支持我的上述假设。

总而言之,除了Test3的行为可能有点“未记录”之外,所有内容都可以通过对手册的引用来解释。

答案 2 :(得分:0)

  

据我了解并阅读,$ @变成“arg1”“arg2”“arg3”。

不,"$@"变为"arg1" "arg2" "arg3"。引号很重要。