Shell(Bash)单引号、双引号和反引号用法详解

单引号和双引号用于变量值出现空格时,比如 name=zhang san 这样执行就会出现问题,而必须用引号括起来,比如 name="zhang san"。

不过,引号有单引号和双引号之分,二者的主要区别在于,被单引号括起来的字符都是普通字符,就算特殊字符也不再有特殊含义;而被双引号括起来的字符中,"$"、"\"和反引号是拥有特殊含义的,"$"代表引用变量的值,而反引号代表引用命令。还是来看例子吧:

[root@localhost ~]# name=sc
#定义变量name的值是sc
[root@localhost ~]# echo '$name'
$name
#如果输出时使用单引号,则$name原封不动地输出
[root@localhost ~]# echo "$name"
sc
#如果输出时使用双引号,则会输出变量name的值sc
[root@localhost ~]# echo `date`
2013 10月 21 日星期一 18:16:33 CST
#反引号的命令会正常执行
[root@localhost ~]# echo '`date`'
'date'
#但是如果反引号括起来的命令又被单引号括起来,那么这条命令不会执行,`date`会被当成普通字符输出
[root@localhost ~]# echo "`date`"
2013年 10月 21 日星期一 18:14:21 CST
#如果被双引号括起来,那么这条命令又会正常执行

所以,如果需要在双引号中间输出"$"和反引号,则要在符号前加入转义符"\"。

反引号

如果需要调用命令的输出,或把命令的输出赋予变量,则命令必须使用反引号包含,这条命令才会执行,反引号的作用和 $(命令) 是一样的,但是反引号非常容易和单引号搞混,所以推荐大家使用 $(命令) 的方式引用命令的输出。命令如下:

[root@localhost ~]# echo ls
ls

如果命令不用反引号包含,那么命令不会执行,而是直接输出

[root@localhost -]# echo `ls`
anaconda-ks.cfg install.log install.log.syslog sh test testfile
#只有用反引号包含命令,这条命令才会执行
[root@localhost ~]# echo $(date)
2013年 10月 21 日 星期一 18:25:09 CST
#使用用$(命令)的方式也是可以的

还是这句话,不管是从容易混淆的角度,还是从 POSIX 规范的角度来说,尽量使用 $(命令) 的方式来引用命令的输出,而不要使用反引号。

Shell(Bash)小括号和大括号用法及区别

在介绍小括号和大括号的用法及区别之前,我们先解释两个概念:父 Shell 和子 Shell。

在 Bash 中,是可以调用新的 Bash 的,比如:

[root@localhost ~]# bash

这时,可以通过 pstree 命令査看一下进程数,命令如下:

[root@localhost ~]# pstree
init──┬──abrt-dump-oops
…省略部分输出
├─sshd──┬──sshd───bash───bash───pstree
…省略部分输出

可以看到我们的命令都是通过 ssh 远程服务链接的,在 ssh 中生成了第一个 Bash,就是父 Shell。因为我们刚刚执行了 Bash 命令,所以在第一个 Bash 中生成了第二个 Bash,这个 Bash 就是子 Shell,我们是在子 Shell 中运行命令 pstree 的。

关于父 Shell 和子 Shell,大家可以想象成在 Windows 中我们开启了一个"cmd"字符操作终端,那么 Windows 本身就是父 Shell,而"cmd"终端则是子 Shell;也可以理解为在一个操作界面中又开启了一个操作界面。

知道了父 Shell 和子 Shell,我们接着解释小括号和大括号的区别。如果用于一串命令的执行,那么小括号和大括号主要区别在于:

  • () 执行一串命令时,需要重新开启一个子 Shell 来执行。
  • {} 执行一串命令时,在当前 Shell 中执行。
  • () 和 {} 都是把一串命令放田括号里面,并且命令之间用";"隔开。
  • () 最后一条命令可以不用分号。
  • {} 最后一条命令要用分号。
  • {} 的第一条命令和左括号之间必须有一个空格。
  • () 里的各命令不必和括号有空格。
  • () 和 {} 中括号里面的某条命令的重定向只影响该命令,但括号外的重定向则会影响到括号里的所有命令。

下面举几个例子。

[root@localhost ~]# name=sc #在父 Shell 中定义 name 的值是 sc
[root@localhost ~]# (name=liming;echo $name)
liming
#如果用()括起来一串命令,那么这些命令都可以执行
#给name变量重新赋值,但是这个值只在子Shell中
[root@localhost ~]# echo $name
sc
#父Shell中name的值还是sc,而不是liming
[root@localhost ~]#{ name=liming;echo $name;} liming
#但是用大括号来进行一串命令的执行时,name变量的修改是直接在父Shell中进行的
#注意大括号的格式
[root@localhost ~]# echo $name
liming
#name变量的值已经被修改了

其实在执行一串命令时,如果使用的是小括号,则这串命令所做的修改只在子 Shell 中生效,一旦命令执行结束,回到父 Shell 中,这个修改就会丟失;而如果使用的是大括号,则此串命令直接在父 Shell 中执行,命令执行结束后,修改依然会生效。