eval " command \"$@\" "、"$@" 和 "$(echo $@)" 用作参数时的不同行为

eval " command \"$@\" "、"$@" 和 "$(echo $@)" 用作参数时的不同行为

我想通过任意名为 的函数以编程方式将多个参数传递给 Tor 浏览器 (firefox) tor。这是为了命令tor search terms,瞧!我的搜索词。当使用这三种变体时,

~/tor-browser_en-US/Browser/start-tor-browser -search "$(echo $@)"

eval "~/tor-browser_en-US/Browser/start-tor-browser -search \"$@\""

~/tor-browser_en-US/Browser/start-tor-browser -search "$@"

只有前两行似乎执行相同。它们会导致单个 Tor 浏览器窗口搜索任意文本内容的术语。然而,第三行会为每个单词产生一个新的搜索窗口。

为什么会有这种行为?

让我澄清一下。我不是在寻找解决方法,而是只是对有关 bahviour 的解释感兴趣。

答案1

对于第三个版本,您"$*"不需要"$@".

解释

为了说明这一点,让我们设置一些位置参数:

$ set -- arg1 arg2 arg3

现在,让我们用你的echo公式读出它们:

$ printf "%s\n" "$(echo $@)"
arg1 arg2 arg3

让我们看看"$@"它们做了什么:

$ printf "%s\n" "$@"
arg1
arg2
arg3

区别在于"$@"扩展为三个单词而"$(echo $@)"扩展为单个字符串。如果您想要类似的行为"$(echo $@)",您应该使用"$*"

$ printf "%s\n" "$*"
arg1 arg2 arg3

文档

man bash

"$*"产生单个字符串:

“$*”相当于“$1c$2c...”,其中 c 是 IFS 变量值的第一个字符。

相比之下,产生一系列单词的man bash状态:$@

“$@”相当于“$1”“$2”...

使用评估

观察:

$ echo 'printf "%s\n" "' "$@" '"'
printf "%s\n" " arg1 arg2 arg3 "

当 bash 计算echo命令时,"$@"扩展为单独的单词。 echo然而,将这些单独的单词组合成一个字符串。我们之前在查看时看到了这一点"$(echo $@)"eval工作原理类似。它从所有参数中生成一个字符串,并计算该字符串。因此:

$ eval 'printf "%s\n" "' "$@" '"'
 arg1 arg2 arg3 

这也被记录在案man bash

评估[参数...]
args 被读取并连接在一起形成一个命令。然后该命令由 shell 读取并执行,...

答案2

考虑一个更简单的例子来看看区别:

$ set "a b" c "d e"
$ printf "%s\n" "$@"
a b
c
d e

前面的就是你说的应该使用;它简单、容易理解并且正确。

$ printf "%s\n" "$(echo $@)"
a b c d e

这里$@首先展开未引用的(命令替换周围的引号是单独的,尚未应用),因此它相当于$(echo a b c d e), 并且printf在格式字符串后面有一个附加参数。

$ eval "printf \"%s\n\" \"$@\""
a b c d e

此处,$@被引用,但扩展会为eval( printf "%s\n" a bcd e) 生成 3 个单独的参数,这些参数连接成一个命令,生成与上面的数字 2 相同的输出。

相关内容