分类: LINUX
2012-04-13 11:50:33
引子
在写Shell脚本的时候,不可避免地要用到变量,也常常要对变量进行一些基本的处理。比如说前两天在给人演示*nix系统的方便之处时,我举了个文件名批量修改的例子(好吧。。这是个不怎么恰当的例子。。),比如说我们想把.h结尾的文件改成.hpp,那么可以这么做
原理很简单:先找到以”.h”结尾的文件,然后调用rename将结尾的”.h”改成”.hpp”。但是在演示的时候杯具出现了: Snow Leopard默认是没有rename这个程序的。-.-||| 没办法,只好想其他办法:
这个虽然也可以完成任务,但是看上去就比上一条命令复杂多了,尤其是”${i%.h}.hpp”这种用法,显然不如’s/\.h$/\.hpp’看上去直观。虽然之后又想到了其他的替代方案,比如:
但像${i%.h}这种用法确实也会经常碰到,于是我就发扬了下打破沙锅问到底的优秀品质,想搞清楚这种类似的用法,到底还有哪些呢?
Shell Parameter Expansion其实这种用法是有专有名词的,就叫做Shell参数展开(Shell Parameter Expansion)。感兴趣的同学可以直接看GNU Bash Manual中的。
其实最基本的参数展开像这样:
shell会将上述表达式转换为parameter的值,即我们通常用的$parameter. 其中parameter是参数名,之所以用”{}”括起来是为了确保shell不会将紧跟其后的字符也作为变量名的一部分,从而尽可能地避免杯具的发生。比如说:
细心的同学可能会问其实这里说的参数(parameter)不就是我们通常说的变量 (variable)么? 嗯。。其实大部分时候这俩名词的意思基本等同。只不过在Shell中parameter(参数)是variable(变量)的超集: 变量名不能以数字开头,而参数名可以。比如说$1就表示命令行传入的第一个参数。
除去最基本的参数展开之外,还有很多种比较灵活的用法如下:
1. 间接展开相当于${var},而var=${parameter}。比如说:
作用: Shell会将其替换为$parameter的长度。
例子:
截取又分两种操作,”掐头”和”去尾”。与正则表达式中不同,头和尾在这里对应的符号分别是”#”和”%”。
掐头:
作用: 从parameter头部开始匹配word,并删除成功匹配的部分。在构造word时可以使用”*”表示任意长度字符,”?”表示单位长度字符,并可用形如”[a-c]“的方式来指定匹配”abc”中的任意字符。
另外,”#”和”##”的区别在于前者是最短匹配,而后者是最长匹配;实际上就是正则表达式中的”懒惰”和”贪婪”的概念。下面的例子能够很清楚地看出这两者的区别。比如说:
去尾:
作用: 与掐头相同,唯一不同的是从$parameter的尾部开始匹配。
例子:
匹配示例中的”.*”时, shell会从$var的尾部开始查找”.”,如果是最短匹配(第一个示例),则找到第一个”.”就停止,否则(第二个示例)会一直找到最后一个”.”才 停止。可以看到,这种用法可以很方便地去掉文件后缀,从而得到文件名,正是本文开头所用到的方法。
4. 字符串替换格式:
作用: 将$parameter中出现的第一个pattern替换为string。值得注意的是,除了”*”, “?” 和”[]“以外,pattern的头部还可以使用下面几个字符:
“/”: 如果pattern以”/”起始,则所有的匹配项都要替换。而默认的行为只是替换最左侧的一个。
“#”: 如果pattern以”#”起始,则与正则表达式匹配规则相同,只有在$parameter的头部找到匹配项才会进行替换。
“%”: 与”#”类似,只是这次变成了尾部匹配。
例子:
格式:
作用: 从offset处开始,截取$parameter中长度为length的子串。其中offset如果为负数的话,表示从尾部开始数。并且要注意这时 候”:”和offset之间至少要有一个空格,不然shell会当成”:-”处理,这个是后面要介绍到的空参数处理操作符。比如:
Shell会自动将其展开为所有以prefix开头的参数名。如:
在这个部分介绍的操作符都是与空参数相关的,而空参数就是值为空,或unset掉的参数。比如说:
或
这样操作后的参数var就是一个空参数。
parameter不为空则用$parameter,不然就用word。例子:
这样实际上是为parameter提供了一个默认值。类似swith..case中的default语句。
如果parameter不为空,就返回word。
例子:
除了上面介绍到的之外,shell参数展开还有很多其他的用法,比如说转换大小写,返回有效的数组下标等等。具体的请参见GNU bash manual.
另外再介绍篇文章:
Linux tip: Bash parameters and parameter expansions