变量和引用(3)

来源:互联网 发布:梦幻花园网络无法连接 编辑:程序博客网 时间:2024/06/05 18:59
这是一篇详细讲解“引用”的文章。
这一篇我们主要讨论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
$
这两个例子的效果是一样的,请对比理解。
原创粉丝点击