我刚刚开始学习 Bash,因此对于以下可能看起来过于基础的问题,我深感抱歉。
我很难理解 Shell 脚本中引号的使用。
如果我要写
a="file"
b="`grep " a" "$a"`"
echo $b
它们应该在引号“`grep " a" "$a"`" 中被读作“$a”和“a”吗?
或者,它是从左到右读的?
因为我被教导用双引号将变量括起来。
更让我困惑的是,我的老师告诉我,为了防止系统误解变量名及其后面的文本,我们应该在变量名周围添加另一个双引号。
嵌套引号有什么作用?我们什么时候应该使用引号?
答案1
普通引号不能嵌套,但反引号在双引号中比较特殊。
使用它$()
代替反引号更具可读性和更简洁。它们的意思都是命令替换,即它们扩展到它们所包含的命令的输出。
b="$(grep " a" "$a")"
但是您不需要在赋值中使用外部双引号,因此以下内容是等效的:
b=$(grep " a" "$a")
您的问题已更改,因此让我们添加更多详细信息:您应该在想要防止分词的任何地方使用双引号。变量名称的问题最好地证明在
echo "$var1_$var2" # two variables, $var1_ and $var2
echo "$var1"_"$var2" # two variables, $var1 and $var2, separated by an underscore
# also possible:
echo "${var1}_$var2"
答案2
由于您使用了带有反引号的命令替换的古老形式,因此答案是“这取决于”。某些 shell(例如 Bash)使用反引号启动一个新的引用上下文,因此内部双引号对嵌套在反引号和外部双引号内,最终得到以下四个引用部分:
b="`grep " a" "$a"`"
# c--c d--d
# b--------------b
# a----------------a
但是...其他一些 shell (ksh) 会对其进行解析,以便第二个双引号结束双引号字符串,而不管中间的反引号如何。结果是这样的:
b="`grep " a" "$a"`"
# a------a b-b c-c
这并不能达到你想要的效果。(它运行grep ''
,将其输出分配给b
,然后运行a
,并使用由空命令替换给出的参数。)
毫不奇怪,POSIX 没有定义这种情况。
也就是说,如果您要更改为使用$(...)
命令替换的形式,您将避免这种情况,并且在这种情况下,扩展总是启动一个新的引用上下文,因此它嵌套在双引号内,并且双引号内内巢内$(...)
。
b="$(grep " a" "$a")"
# c--c d--d
# b--------------b
# a-----------------a
看:
请记住,朋友不要让朋友使用反引号。
更让我困惑的是,我的老师告诉我,为了防止系统误解变量名及其后面的文本,我们应该在变量名周围添加另一个双引号。
为此,您可以使用引号,或在变量名称两边加上大括号。因此,在所有三种变体中,下面都$foo
进行了扩展并附加了固定字符串bar
:
$ foo=xxx
$ echo "$foo""bar" "$foo"bar "${foo}bar"
xxxbar xxxbar xxxbar
最后一篇可能是最容易阅读的。
嵌套引号有什么作用?我们什么时候应该使用引号?
如上所述,如果没有命令替换之类的内容,引号不会相互嵌套。如果没有一个,类似的引号只是结束引用,而其他引号就像普通字符一样,不引用任何内容。
例如,这是两个带引号的字符串,中间有一个不带引号的部分:
"foo "abc def" bar"
# <----> <---->
# ^ unquoted space.
这是一个带引号的字符串,恰好包含单引号字符:
$ echo "foo 'abc def' bar"
foo 'abc def' bar
echo
单引号作为命令行参数的一部分传递,就像字母和空格一样。他们不引用任何内容。
至于什么时候,请看:什么时候需要双引号?