Shell还有另一种方式可以把多个命令组合起来,把这些命令的执行结果汇集到一起输出,从而可以通过管道送给下一个命令一起处理。有两种方式可以实现该目的,{ }和( )。
1. 大括号{}
第一种方式是使用大括号{ }。下面的例子是给每一种蕨类植物(在文件fern中)的拉丁学名前加上类群名fern,每一种苔藓植物(在文件moss中)拉丁学名前加上类群名moss,然后把两种植物处理的结果一起输出并排序:
[peter@ibi-genome plant]$ ls fern moss [peter@ibi-genome plant]$ cat fern Selaginella sinensis Selaginella moellendorfii [peter@ibi-genome plant]$ cat moss Physcomitrella patens [peter@ibi-genome plant]$ { sed 's/^/moss\t/' moss; sed 's/^/fern\t/' fern; } |sort fern Selaginella moellendorfii fern Selaginella sinensis moss Physcomitrella patens
注意,左边的大括号后面需要有一个空格,并且每一个命令的后面都要有一个分号。
2. 小括号()
第二种方式是使用小括号( ),效果与使用大括号是一样的:
[peter@ibi-genome plant]$ (sed 's/^/moss\t/' moss; sed 's/^/fern\t/' fern) |sort
fern Selaginella moellendorfii
fern Selaginella sinensis
moss Physcomitrella patens
使用小括号组合命令时,左边的小括号后面不需要空格,最后一个命令的后面也可以不要分号。
虽然上面两种方式执行的效果一样,但执行的过程是有差别的。{ }里面的命令在当前Shell中执行,而( )中的命令在执行时新建一个子Shell,其中的变量值不会影响当前Shell。我们通过下面的例子来加深一下对这两种方式的区别的理解。
[peter@ibi-genome plant]$ echo $a #当前Shell中,变量a没有赋值 [peter@ibi-genome plant]$ echo $b #当前Shell中,变量b没有赋值 [peter@ibi-genome plant]$ { a=animal; echo $a; } #大括号里给变量a赋值 animal [peter@ibi-genome plant]$ echo $a #当前Shell里变量a有值了 animal [peter@ibi-genome plant]$ (b=plant; echo $b) #在小括号中给变量b赋值 plant [peter@ibi-genome plant]$ echo $b #在当前Shell中变量b仍然没有值
Shell中变量无需定义,可以直接赋值,赋值时前面没有$,引用时前面需加$。关于变量,我们在下一节用户自定义变量中还要详细学习。
在上面的例子中,在大括号中给变量a赋值,也就是在当前Shell中给变量a赋值,因此离开大括号在当前Shell中用echo显示变量a的值也是animal。而在小括号中给变量b赋值,由于小括号中的命令是在一个新的子Shell中运行,该变量只在这个子Shell中有效,离开了这个子Shell,变量b还是没有赋值。
如果把当前Shell比作一个大房间,用大括号组合命令就像只是逻辑上把大房间里的几个人分成一组,他们做事情还是与其他人一起在大房间里做;而用小括号组合命令就像给几个人单独在其中再开一个小房间,他们在里面做什么都不会影响外面,只需要最后完成任务就可以了。