shell中的引用详解--<转>

本文转自http://licong.blog.51cto.com/542131/211929

原作者:licong_jay

这一篇我们主要讨论shell中的引用,本篇内容不多,之所有要单独篇幅来讨论是因为它很重要而且相对比较独立。我们要介绍的引用方法包括以下内容:

单引号’

双引号”

反斜杠\

反引号`

命令引用$( )

 

一、单引号

我们前面介绍了变量,还介绍了文件名替换中的特殊符号*和命令行中空格的意义。如果变量或者命令行中出现了shell特殊字符,应该怎么处理呢?还是举例子吧:

$ cat phonebook

Alice Chebba    973-555-2015

Barbara Swingle 201-555-9257

Billy Bach      201-555-7618

Liz Stachiw     212-555-2298

Susan Goldberg  201-555-7776

Susan Topple    212-555-4932

Tony Iannino    973-555-1295

$ grep Susan phonebook

Susan Goldberg  201-555-7776

Susan Topple    212-555-4932

$

我们知道,grep可以知道含有特定模式的行,这里找出了显示了包含字符Susan的行,结果有2行。如果我们想精确查找Susan Goldberg所在的行呢?

$ grep Susan Goldberg phonebook

grep: Goldberg: No such file or directory

phonebook:Susan Goldberg        201-555-7776

phonebook:Susan Topple  212-555-4932

$

可以看到,shell先抛出了一个错误,然后显示了包含Susan的行,而且前面还有文件名,这一系列的结果似乎并不在我们的意料之内。我们先来回顾一下grep的语法规则:

grep pattern file(s)

按照这个规则,我们不难理解shell在想些什么:命令行

grep Susan Goldberg phonebook

中,Susan是模式pattern,而Goldberg和phonebook都是文件名(shell这么理解的)。所以shell会告诉我们grep: Goldberg: No such file or directory(文件或目录不存在)。尽管shell判断文件Goldber不存在,它依然认为我们给了它两个文件名,所以结果出现的文件名phonebook就在情理中了。

回到我们的问题,精确查找Susan Goldberg所在的行。我们需要把Susan Goldberg(包作为pattern给grep处理,包括之间的空格。这时我们需要去除空格在shell中特殊意义(还记得吗,空格是命令行参数分隔符之一),单引号可以帮我们解决这个问题:

$ grep 'Susan Goldberg' phonebook

Susan Goldberg  201-555-7776

$

这次我们得到了想要的结果,shell去掉了空格的特殊意义,把Susan Goldberg当作pattern来处理了。单引号的作用就是屏蔽shell中特殊字符的意义,使他们变成普通字符。

成对的单引号可以屏蔽所有字符,甚至是换行符。还是继续看例子:

$ file=/home/steve/bin/prog1

$ echo $file

/home/steve/bin/prog1

$ echo ‘$file’

$file

$

使用单引号引用$file时,shell原封不动的显示了它们。这时符号$的变量替换意义被屏蔽了。

$ echo *

1.bak  2.bak  3.bak  urfile

$ echo ‘*’

*

$

使用单引号引用*时,shell原封不动的显示了*。这时符号*的文件名替换意义被屏蔽了。

当使用单引号对时,我们甚至不需要知道什么符号有特殊意义。


二、双引号

双引号和单引号的作用差不多,区别在于双引号没有那么严格。单引号告诉shell屏蔽所有字符的特殊意义,而双引号只要求忽略大多数。具体地说,括在双引号中的以下三种字符不被屏蔽:

美元符号$

反斜杠\

反引号`

不屏蔽美元符号的特殊意义,意味着在双引号内部也进行变量名替换。

$echo “$file”

/home/steve/bin/prog1

$

变量file的值被显示了出来。

$ x=*

$ echo $x

1.bak  2.bak  3.bak  urfile

$ echo “$x”

*

$

这个例子中,变量x的值*被替换并显示了出来。为什么结果不是文件名的列表呢?x变量被替换后,结果为

    echo “*”

*在双引号中也是被屏蔽的(不屏蔽的只有$等三中符号),所以结果只显示*。所以,如果希望替换变量的值,而又不希望shell把替换的结果当做特殊字符对待,就应该把变量名放在双引号中。

可以用双引号来对shell隐藏单引号,反之亦然。


三、反斜杠

反斜杠\的作用与单引号相似,能够屏蔽所有字符(包括反斜杠)的特殊意义。与单引号的区别在于:

1、  反斜杠不用成对出现,而单引号必须成对

2、  反斜杠只屏蔽紧跟在之后的单个字符,评比多少字符就需要多少个反斜杠

换句话说,反斜杠等于在一个字符前面加上单引号,也有一些小小的意外。

$ echo >

-bash: syntax error near unexpected token `newline'

$ echo \>

>

$

第一种情况下,shell看到>会把它解释为输出重定向符号,并期待在后面你输入一个文件名。由于没有输入文件名而直接回车了,所以shell发出错误信息。反斜杠去掉了>的特殊意义,直接由echo输出。

$ x=*

$ echo \$x

$x

$

这个例子中,shell屏蔽了反斜杠后面的$,结果不作变量替换。

$ echo \\

\

$ echo ‘\’

\

$

上面两条命令中,反斜杠都被屏蔽了。当然,第一条命令中屏蔽的是后面一个反斜杠。

用反斜杠续行

我们再来看一下前面提到的“小小的意外”,当反斜杠用于一行的最后一个字符时:

$ lines=one’

>’two

$ echo “$lines”

one

two

$ lines=one\

>two

$ echo “$lines”

onetwo

$

shell把行尾的反斜杠作为续行,它去掉跟在后面的换行字符,也不把换行符当作参数分隔符(就像该字符从来没有键入过一样)。这种结构在分几行键入命令时经常使用。

双引号中的反斜杠

我们知道,反斜杠是双引号要解释的三个特殊符号之一。因此我们可以再双引号中用反斜杠来屏蔽这三种字符,此外还能用这种方法屏蔽双引号中的双引号:

$ echo “\$x”

$x

$ echo "`aa` is a command"

-bash: aa: command not found

 is a command

$ echo "\`aa\` is a command"

`aa` is a command

$ echo "\" is a spec char"

" is a spec char

$

当反引号前面没有反斜杠时,上面的`aa`报错:没有aa命令。说明双引号不屏蔽反引号的功能,而加了反斜杠就被屏蔽了。

当双引号中的反斜杠后面不是一个双引号不能屏蔽的符号,会出现什么情况呢?键入

echo “\’ is a spec char”

会出现什么结果呢?是

‘ is a spec char

吗?开始我也是这么认为呢,可是错了,结果是

\' is a spec char

当双引号中的反斜杠后面不是一个双引号不能屏蔽的符号时,反斜杠保留字面意义。我们再看几个复杂点的例子:

$ x=5

$ echo "The value of x os \"$x\""

The value of x os "5"

$

要想在终端显示以下一行文字:

<<< echo $x >>> displays the value of x, which is $x

我们要替换第二个$x中的x值,第一个$x保留原样。直接用echo命令跟上上面那句话,会出现什么情况呢?

$ echo <<< echo $x >>> displays the value of x, which is $x

-bash: syntax error near unexpected token `>'

$

显然,重定向报错。

$ echo "<<< echo $x >>> displays the value of x, which is $x"

<<< echo 5 >>> displays the value of x, which is 5

$

这也不是我们要的结果,换成单引号呢?两个$x都会保留原样。下面我们用2种不同的方法实现来得到我们想要的结果:

$ echo "<<< echo \$x >>> displays the value of x, which is $x"

<<< echo $x >>> displays the value of x, which is 5

$ echo '<<< echo \$x >>> displays the value of x, which is' $x

<<< echo $x >>> displays the value of x, which is 5

$

第二中方法最安全的做法,是将最后的$x也用双引号引用起来,防止x值中有其他特殊字符(当然本例没有)。


四、反引号和$( )

反引号` `和$( )都用来替换命令的,格式分别如下:

`command`

$(command)

可以像使用一般shell变量那样,使用命令替换,替换得到的结果就是命令command的结果。看几个例子:

$ echo "Today is `date`"

Today is Tue Sep 29 15:44:25 EDT 2009

$echo "Today is $(date)"

Today is Tue Sep 29 15:44:25 EDT 200

$

` `和$( )的主要区别仅在于他们的形式。相对来说,$( )更为常用一些。因为` `和单引号、双引号混在一起时很容易让人眼花缭乱,而且他们是经常出现在一起的。

命令替换同样可以用在赋值语句里,就像普通变量一样。

$ file=/home/steve/memos

$ firstchar=$(echo $file | cut –c1)

$ file=$(echo $file | tr “$firstchar” “^”)

$ echo $file

^home^steve^memos

$

也可以用一个嵌套的命令替换来完成同样的操作:

$ file=/home/steve/memos

$ file=$(echo $file | tr “$(echo $file | cut -c1)” "^")

$ echo $file

^home^steve^memos

$

这两个例子的效果是一样的,请对比理解。

本文出自 “licong” 博客,请务必保留此出处http://licong.blog.51cto.com/542131/211929

标签:Linux, Shell

评论已关闭