这个问题我想了很久,但一直不知道怎么查
这是:
x=`command -v r2g`
与此相同:
x="$(command -v r2g)"
还是与此相同:
x=$(command -v r2g)
...如果是后者,我应该这样做来解决它吗?
x="`command -v r2g`"
答案1
所有示例都是来自命令替换的变量赋值,因此它们是等效的。按照吉尔斯的答案,在变量赋值的右侧不需要引用,因为那里不会发生分词。所以四个都OK。
如果它们是独立的,即不在作业中,那么您需要引用。与反引号相比,这种 $(...)
形式的优点是引号可以嵌套并分成多行,这就是为什么现在普遍首选这种形式。换句话说,您可以"$( echo "$var" )"
使用此形式来保护 的内部扩展$var
和外部扩展$(...)
免受分词和文件名通配的影响。
如图所示POSIX Shell 命令语言根据规范,嵌入式多行脚本不能使用反引号(左侧),但可以使用$()
表单(右侧)。
echo ` echo $(
cat <<\eof cat <<\eof
a here-doc with ` a here-doc with )
eof eof
` )
echo ` echo $(
echo abc # a comment with ` echo abc # a comment with )
` )
echo ` echo $(
echo '`' echo ')'
` )
答案2
这四个示例在功能上是等效的。
反引号已经过时了,除非您使用 1970 年的 shell,如 Bourne shell(如 Heirloom),否则您不需要它们。主要问题是他们是很难筑巢, 尝试:
$ echo $(uname | $(echo cat))
Linux
$ echo `uname | `echo cat``
bash: command substitution: line 2: syntax error: unexpected end of file
echo cat
在只有一个赋值的命令行的右侧,没有必要(但无害)引用扩展,因为无论如何扩展都被认为是引用的:
$ var=$(uname)
但那就是不是始终为 true,命令导出上的赋值被视为参数,并将在某些 shell 中进行 split 和 glob(不是在 bash 中):
$ dash -c 'export MYVAR=`echo a test`;echo "$MYVAR"'
a
同样的推理适用于local
(局部变量赋值需要引号吗?)和declare
(以及其他一些)。
您应该做的“修复它”是:
x=$(command -v r2g)
有时(对于可移植脚本):
export x="$(command -v r2g)"
答案3
是的,反引号也应该被引用。
对于命令输出不包含空格的情况,这可能是首选 bash 样式的问题。以下是该实用程序作者的引述shellharden
,摘自“如何在 bash 中安全地做事”:
Should I use backticks?
Command substitutions also come in this form:
Correct: "`cmd`"
Bad: `cmd`
While it is possible to use this style correctly, it looks even more awkward in quotes and is less readable when nested. The consensus around this one is pretty clear: Avoid.
Shellharden rewrites these into the dollar-parenthesis form.
我还相信用 引用反引号"
,或者(更好)重写它以使用 是很好的形式$()
。如果使用反引号时命令输出包含空格或特殊字符,如果不引用表达式可能会出现问题。
答案4
是的,根据这份文件,我的猜测看起来是正确的: https://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md
它说:
# Should I use backticks?
# Command substitutions also come in this form:
Correct: "`cmd`"
Bad: `cmd`