前言

请原谅我的标题党,这篇文章主要聚焦的是 linux shell 中的引号问题。

如果你正在和 shell 打交道,那么了解 shell 中关于引号的问题是一件很有必要的事情。

下面的这些规则适用的对象是 POSIX 兼容的 shell 例如我们常用的 bash(GNU Bourne-Again Shell)。

: 注意我的措辞,单独的引号的意思是既可以是单引号也可以是双引号。单引号和双引号就是本来的意思。括起来的意思是,文本被左右引号包裹起来,例如: 'foo', "bar "

下面的一些例子使用了 awk 这个命令行工具进行实例,使用的是最简单的 awk 语法,主要是展示 shell 的解释器是怎么处理传给它的文本的。

规则和例子

我们先创建一个叫做 shell-test.sh 的文件,接下来的例子直接放到我们的脚本内,然后执行 sh shell-test.sh,即可得到输出结果。

  • 被引号括起来的东西, 和其他没被引号括起来的东西, 是可以被链接为一个整体的。

例子:

1
2
3
4
#!/bin/bash
# \t 是制表符, \47 是一个单引号

awk 'BEGIN {print "'-F'\t\47foobar'\tddd'" }'

在命令行试验一下,得到结果:

1
-F      'foobartddd
  • 任何用反斜线作为前缀的一个字符,会被 shell 先去掉反斜线后,原封不动的传给指定的命令

: 这里没有说要把字符和前缀括起来。

例子:

1
2
3
#!/bin/bash

awk 'BEGIN {print "hello\thello'\t' " }'

执行一下脚本,看看结果:

1
hello   hellot

请注意,这里的第一个 \t 被解释成了制表符,而第二个 \t 直接被解释成了 t 字符串。

  • 单引号会保护所有在前后单引号内部的文本,将它们原封不动的传给命令,shell 不会对内部作替换。

例子:

1
2
3
#!/bin/bash

awk 'BEGIN {print "'\t'" }'

执行一下脚本,看看结果:

1
t
  • 双引号内部的代码块会被 shell 解释和处理。所以对于特别的字符,如果需要传递纯文本,要使用下划线 + 字符的写法。

例子:

1
2
3
#!/bin/bash

awk 'BEGIN {print "\\\$" }'

执行一下脚本,看看结果:

1
\$

小结

说实话,shell 里面的这些字符的解释真的很诡异。

有一个比较简单的理解是,解释器是从左到右解释的,它只会简单地去找下一个匹配上的引号。而 shell 里的引号,可以理解为是一种开关,让 shell 解释器理解到底应该如何操作。

end