赞
踩
每次输入命令行按下Enter键时,bash都会在执行命令之前对文本进行多重处理。前面已经见过一个简单的字符序列(比如*)在shell中被识别为多种意思的例子。产生这种结果的处理过程称为扩展(expansion)。有了扩展功能,在输入内容后,这些内容将在shell对其执行之前被扩展成其他内容。为了证明这点,让我们先来看看echo命令。echo是shell的一个内置命令,它执行的任务非常简单,即把文本参数内容打印到标准输出。
这个例子相当简单,传递给echo的任何参数都将显示出来的。
再看另一个例子
为什么echo输出的不是*
?
*
字符意味着“匹配文件名中的任意字符”,但是之前我们并没有讨论shell是如何实现这个功能的,答案很简单,shell会在执行echo命令前把*
字符扩展成其他内容(在这个例子中,扩展为当前工作目录下的所有文件名)。在按下Enter键的时候,shell会在执行命令前自动扩展命令行中所有符合条件的字符,因此echo命令将不可能看到*
字符,只能看到*
字符扩展后的结果。
通过使用通配符来实现扩展的机制称为路径名扩展(pathname expansion)。
下面给定一个主目录:
执行下面的扩展:
以及
甚至是
查看除主目录之外的目录
文件名以.
点字符开头的文件都将被隐藏。路径名扩展功能也遵守这个规则。类似echo *这样的扩展并不能显示隐藏的文件,需采用精确的模式:
ls -d .[!.]?*
这种模式将扩展为以一个点字符开头的所有文件名,文件名中并不包含第二个点字符,但包含至少一个额外的字符,后面也可能还跟着其他的字符。
波浪线字符(~)具有特殊的含义,如果把它用在一个单词的开头,那么它将被扩展为指定用户的主目录名;如果没有指定用户名,则扩展为当前用户的主目录。
如果有ding这个用户
shell支持通过扩展来运行算数表达式。这允许我们把shell提示符当做计算器来使用。
算数扩展使用如下格式
$((expression))
其中,expression是指包含数值和算数操作符的算数表达式。
算数扩展只支持整数(全是数字,没有小数),但是可以执行很多不同的运算。
运算符 | 描述 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除(但是记住,因为扩展只支持整数运算,所有结果也是整数) |
% | 取余,即余数 |
** | 取幂 |
空格在算数表达式中是没有意义的,而且表达式是可以嵌套的。例如把5^2和3相乘。
你可以使用一对括号来组合多个子表达式。通过该技术,可以把上面的例子重写,用一个扩展来代替两个,可以得到同样的结果。
下面的例子使用了除运算符和取余运算符,注意整数相处的结果。
花括号扩展(brace expansion)可能算是最奇怪的扩展方式了。有了它,你可以按照花括号里面的模式创建多种文本字符串。
示例如下:
用于花括号扩展的模式信息可以包含一个称为前导字符(preamble)的开头部分和一个称为附言(postscript)的结尾部分。花括号表达式本身可以包含一系列逗号分隔的字符串,也可以包含一系列整数或者单个字符。这里的模式信息不能包含内嵌的空白。
下例为一系列整数
下例为一系列逆序排列的字母
花括号扩展支持嵌套
那么花括号扩展一般应用于什么地方呢?最普遍的应用是创建一系列的文件或者目录。比如说,你有一个很大的图片集,想要按照年份和月份来对这些图片进行分组,那么要做的第一件事就是创建一系列以年月格式命名的目录。这样,这些目录名将会按照年代顺序排列,输出目录的一个完整的列表、但是这样做工作量大,而且容易出错,为此我们可以用花括号扩展。
参数扩展用在shell脚本中比直接用在命令行中更为有用。它的许多特性与系统存储小块数据以及给每个小块数据命名的性能有关。许多这样的小块数据(称为变量【variable】会更合适)可用于扩展。
例如,命名为USER的变量包含你的用户名,为了触发参数扩展,并显示出USER的内容,你可以进行如下操作:
想要查看可用的变量列表,试试如下操作:
对应其他的扩展类型来说,如果你误输入了一个模式,就不会发生扩展,这时echo命令将只是显示这些误输入的模式信息。但是对于参数扩展来说,如果变量名拼写错误,仍然会进行扩展,只不过结果是输出一个空字符串而已,如下所示:
命令替换可以把一个命令的输出作为一个扩展模式使用,如下图所示:
我比较喜欢下面这种用法:
这里,把which cp命令的运行结果作为ls命令的一个参数,因此我们无需知道cp程序所在的完整路径就能获得cp程序对应的列表。这个功能并不只是局限于简单的命令,也可以应用于整个管道中(只不过只显示部分输出内容)。
在这个例子中,管道的输出为file命令的参数列表。
在早期的shell程序中,存在命令替换的另一种语法格式,bash也支持这种格式。它用反引号代替美元符号和括号,具体如下:
我们已经知道,shell有多种方式可以执行扩展,现在我们来学习如何控制扩展。
先看下面这个例子:
再看这个例子:
在第一个例子中,shell会对echo命令的参数列表进行单词分割(word splitting),去除多余的空白。在第二个例子中,因为$1
是一个未定义的变量,所有参数扩展将把$1
的值替换为空字符串。shell提供了一种称为引用的机制,用来有选择性的避免不想要的扩展。
我们要看的第一种引用类型是双引号。如果把文本放在双引号中,那么shell使用的所有特殊字符都将失去它们的特殊含义,而被看成普通字符。字符“$(美元符号)”,“\(反斜杠)”,“ ’ (反引号)”除外。这就意味着单词分割,路径名扩展,波浪线扩展和花括号扩展都将失效,但是参数扩展,算数扩展和命令替换仍然生效。使用双引号能够处理文件名中包含空白的情况。假设不幸地有一个名为two words.txt的文件,如果在命令行中使用该文件名,那么单词分割功能将把它当成两个独立的参数,而不是当成我们希望的单个参数,具体运行结果如下:
使用双引号能组织单词分割,得到预期的结果。另外,使用双引号甚至可以修复破损的文件名。
这样一来就不需要一直输入双引号了。
请记住,参数扩展,算数扩展和命令替换在双引号中依然生效。
我们已经知道,单词分割可以去除文本中多余空白的情况
默认情况下,单词分割会查找是否存在空格,制表符以及换行(换行字符),然后把它们当做单词间的界定符。这就意味着没有引用包含起来的空格,制表符和换行字符都不会被当成文本的一部分,而只是被当成分割符。因为它们把这些单词分割成不同的参数,所以例子中的命令行被识别为命令后面跟着4个不同的参数。但是如果加上双引号,单词分割功能将失效,嵌入的空格将不再被当成界定符,而是被当成参数的一部分。
一旦加上双引号,那么命令行将被识别为命令后面只跟着一个参数。
单词分割机制会把换行字符当成界定符,这一点在命令替换的时候将会产生微妙的效果。
在这第一个例子中,没有加上引号的命令替换将导致命令行被识别为命令后面跟着38个参数;而在第二个例子中加了双引号,使得命令行被识别为命令后面只跟着一个参数,这个参数包含着嵌入的空格和换行字符。
如果我们希望抑制所有的扩展,那么应使用单引号。
可以看到,随着引用级别的加强。越来越多的扩展将被抑制。
有时候我们想要引用个单个字符,这种情况可以通过在该字符前加上反斜杠来实现。这里的反斜杠称为转义字符。转义字符经常出现在双引号中用来选择性阻止扩展。
转义字符也常用来消除文件名中的某个字符的特殊含义。比如,文件名中可以使用在shell中通常具有特殊含义的字符。这些字符包括“$”,“!”,“&”,空格等。要想在文件名中包含特殊字符,可执行如下操作:
如果想要显示反斜杠字符,可以通过使用两个反斜杠“\”来实现。需要注意的是,单引号中的反斜杠将失去它的特殊含义,而是被当做一个普通字符。
转义字符 | 含义 |
---|---|
\a | 响铃(警告声) |
\b | 退格 |
\n | 新的一行(在类UNIX系统中,产生的是换行效果) |
\r | 回车 |
\t | 制表 |
表中列出了一些常用的反斜杠转义字符序列。使用反斜杠来表示转义字符表示的理解来源于C语言,其他语言也采用了这种表示方法,包括shell。
在echo命令中带上-e选项,就能够解释转义字符序列。也可以将其放在“$‘’”中。
在下面这个例子中,只需要使用sleep命令(它是一个简单的程序,在等待指定的秒数之后就会退出),就可以创建一个简单的倒计时的计时器:
sleep 10; echo -e "Time's up \a"
//也可以这样写
sleep 10; echo "Time's up" $'\a'
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。