还是回到我们的 command line 来吧…

经过前面两章的学习,应该很清楚当你在 shell prompt 后面敲打键盘、直到按下 Enter 的时候,你输入的文字就是 command line 了,然后 shell 才会以进程的方式执行你所交给它的命令。

但是,你又可知道:你在 command line 输入的每一个文字,对 shell 来說,是有类別之分的呢?

简单而言,comman line的每一个character,可分为如下两种:

literal:也就是普通纯文字,对shell来说没有特殊功能
meta:对shell来说,具有特定功能的特殊字符,称之为元字符

literal没什么好谈的,abcd、123456这些“文字“都是literal;但meta却常使我们困惑。

事实上,前两种我们在command line中已经碰到两个几乎每次都会碰到的meta(元字符):

IFS:由或或三者之一组成(常用space)
CR:由产生

IFS是用来拆解command line的每一个词(word)用的,因为shell command line是按词来处理的。而CR则是用来结束command line用的,这也是为何我们敲<enter>后命令就会执行的原因。

除了IFS与CR,常用的meat还有:

=    定义变量。
$    作变量或运算替换(请不要与 shell prompt 搞混了)。
>    重定向 stdout。
<    重定向 stdin。
|    命令管道。
&    重定向 file descriptor ,或将命令置于后台执行。
()   将其內的命令置于 nested subshell 执行,或用于运算或命令替换。
{}   将其內的命令置于 non-named function 中执行,或用在变量替换的界定范围。
;    在前一个命令結束时,而忽略其返回值,继续执行下一个命令。
&&   在前一個命令結束时,若返回值为 true,继续执行下一个命令。
||   在前一個命令結束时,若返回值为 false,继续执行下一個命令。
!    执行 history 列表中的命令
....

假如我们需要在command line中将这些保留元字符的功能关闭的话,就需要quoting(引用)处理了。

在bash中,常用的quoting有如下三种方法:

hard quote(强引用):''(单引号),凡在hard quote中的所有元字符均被关闭
soft quote(弱引用):""(双引号),在soft quote中大部分元字符均会被关闭,但某些则保留(如$)
escape:\(转义),只有紧接在escape之后的单一元字符才被关闭

下面的例子讲有助于我们对quoting(引用)的了解。

$ A=B C        # 空格键未被关掉,作为 IFS 处理。
$ C: command not found. 
$ echo $A

$ A="B C"        # 空格键已被关掉,仅作为空格键处理。
$ echo $A
B C

在第一次给变量A赋值时,由于空格键没被关闭,command line将被解读为

A=B 然后碰到IFS,再执行C命令

在第二次给A变量赋值时,由于空格键被置于弱引用中,因此会被关闭,不再作为IFS:

A=B<space>C

事实上,空白键无论在弱引用还是在强引用中,均会被关闭,Enter键亦然:

$ A='B
> C
> '
$ echo "$A"
B
C

在上例中,由于<enter>被置于强引用中,因此不再作为CR字符来处理。这里的<enter>单纯只是一个换行符号(new-line)而已。由于command line没有得到CR字符,因此进入第二个shell prompt(PS2,以>符号表示),command line并不会结束,直到第三行,我们输入的<enter>并不在强引用里面,因此并没有被关闭,此时,command line碰到CR字符,于是结束、交给shell来处理。

上例的<enter>要是置于弱引用中的话,CR也会同样被关闭。

$ A="B
> C
> "
$ echo $A
B C

然而,由于echo $A时的变量没有置于弱引用中,因此当变量替换完成后并作命令行重组时,<enter>会被解释为IFS,而不是解释为New line字符。同样的,用escape亦可关闭CR字符:

$ A=B\
> C\
>
$ echo $A
BC

上例中,第一个<enter>跟第二个<enter>均被escape字符转义而关闭了,因此不作为CR来处理,但第三个<enter>由于没被转义,因此作为CR结束command line。但由于<enter>键本身在shell 元字符中的特殊性,在\转义后,仅仅取消其CR功能,而不会保留其IFS功能。

你或许发现,光是一个<enter>键所产生的字符就有可能是如下这下可能:

CR
IFS
NL(New Line)
FF(Form Feed)
NULL
…

至于什么时候会解释为什么字符,各位自行摸索吧。

至于软引用跟强引用的不同,主要是对于某些元字符的关闭与否,以$来作说明。

$ A=B\ C
$ echo "$A"
B C
$ echo '$A'
$A

在第一个echo命令行中,$被置于软引用中,将不被关闭,因此继续处理变量替换,因此echo将A的变量值输出到屏幕,也就得到”B C”的结果。

在第二个echo命令行中,$被置于强引用中,则被关闭,因此$只是一个$字符,并不会用来做变量替换处理,因此结果是$符号后面接一个字母A。

转载请注明:知识蚂蚁 » shell十三问?(简体中文版)第4问:”"(双引号)与”(单引号)差在哪?

我来说说

(便于我们更好的交流)

有不明白的地方欢迎留言哦~
取消