还是回到我们的 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。