2.3.6 shell内置命令
- trap命令(常被称为陷阱),用于指定在接收到系统信号后所要执行的命令。常用于脚本程序被中断执行时指定需要完成的配置或文件的清理工作。历史上,shell中常用不同的数字来代表不同的信号,现在逐渐使用信号的名字来明确指定信号的类型,这有利于代码的可读性。信号名字在头文件signal.h中定义,使用时需要省略SIG前缀。可以在命令行下使用trap –l查看信号的编号和对应的信号名。(信号是那些被异步发送给程序的事件,默认情况下常会导致程序运行的终止)。trap命令有两个参数,前一个是接受到信号后要执行的命令,后一个是要处理的信号名(或对应的信号值):
trap command signal
由于脚本程序是从起始到结束循序执行的,所以必须在期望保护的代码段之前指定trap命令内容.可以将command设置为-来重置命令的默认处理方式.如果要忽略某个命令可以将command设置为空字符串’’.如下是比较重要的一些信号:
HUP(1) 挂起,终端掉线或用户退出引发INT(2) 中断,Ctrl+C时引发QUIT(3) 退出,常在按下Ctrl+\组合键时引发ABRT(6) 中止,常为某些严重的执行错误引发ALRM(14) 报警,常用于处理超时TREM(15) 终止,常在系统关机时发出
使用举例如下,在循环执行过程中,按下ctrl+C组合键就会触发INT信号,执行相应的命令,最终临时文件被删除,循环条件不在满足,循环退出:
trap 'rm -f /tmp/my_tmp_file_$$' INTdate > /tmp/my_tmp_file_$$while [ -f /tmp/my_tmp_file_$$ ]; doecho file existsdone
- unset命令,从环境中删除相应的变量和函数,类似于清除类变量及其释放对应的内存空间。但不能删除shell本身定义的只读变量(如IFS),这个命令并不常用。举例如下:
foo="Hello world"echo $foounset fooecho $foo #执行结果为空
- find命令,和grep命令虽然都不是shell的一部分,但在编写是常被用到。该命令用于搜索文件(简单的说来就是找你想要的文件及其路径),它的命令的完整内容有选项、测试和动作参数组成,使用较复杂。举例,在本地机器上查找文件名为test的文件:
$ find / -name test -print #请使用root权限执行
该命令的完整语法格式如下:
find [path] [options] [tests] [actions]
path部分:既可以使用绝对路径/bin,也可以使用相对路径.。如果需要还可以指定多个路径,如find /var /home。
options部分有如下参数可选:
-depth 在查看目录前先搜索目录内容-follow 跟随符号链接-maxdepths N 最多搜索N层目录-mount(或-xdev) 不搜索其他文件系统中的目录
tests部分的条件组合很多,但返回的结果只有两种可能:true和false。测试条件将依照定义的顺序依次在搜索到的每个文件上执行,若返回false则跳过该文件继续搜索,为true则继续测试该文件或执行相应的动作。常用的测试如下:
-atime N 文件在N天前最后被访问过-mtime N 文件在N天前最后被修改过-name pattern 文件名匹配模式,为确保内容被find处理而不是shell,该内容常被引号括起来-newer otherfile 文件是否比otherfile要新-type c 文件类型是否为c,或d(目录),或f(普通文件)-user username 文件所有者是否为username
还可以使用如下操作符与测试条件形成组合测试条件,操作符分短格式和长格式:
! -not 条件取反-a -and 两个都为真时为真-o -or 两个测试条件有一个及以上为真时结果为真
还可以使用圆括号括起测试和操作符来调整测试条件的优先级,但圆括号对shell有特殊意义所以要对齐进行转义。使用举例如下,查找当前路径下以下划线开头的文件或比test文件要新的文件,但这两种情况下的文件都必须是普通文件:
$ find . \( -name "_*" -or -newer while2 \) -type f -print
常见的动作actions部分:匹配到指定的文件后,需要执行的命令:
-exec command 执行一条命令,必须以\;结尾-ok command 与-exec类似,但是在执行命令前会针对每个文件要求用户进行确认-print 打印文件名-ls 对当前文件使用ls -dils命令
应用举例如下,魔术字符串是-exec和-ok命令的一个特殊参数,输出文件的完整路径:
$ find . -newer test -type f -exec ls -l {} \;
- grep命令,和find一样几乎是Linux用户必须掌握的命令。全称叫做通用正则表达式解析器(Genneral Regular Expression Parser,简写为grep)。find指令搜索到了文件,grep就可以用于在文件中查找字符串。在实践中常用的方法是将grep作为传递给find命令的-exec的一条命令执行。grep完整的命令内容包括一个选项一个要匹配的模式和要搜索的源文件,语法格式如下:
grep [options] PATTERN [FILES]
如果未提供源文件名则grep将在标准输入中进行搜索。主要选项字段如下:
-c 输出匹配行的数目而不是匹配行内容-E 启用扩展表达式-h 取消每个输出行的普通前缀,即不列出匹配查询模式的文件名-i 忽略大小写-l 只列出存在匹配行的文件的文件名,而不列出匹配行的内容-v 对匹配模式取反,即搜索不匹配行
应用举例,查找不含echo的文件的匹配行数目:
$ grep -c -v echo test.sh f.sh 1.sh 2.txt 3.c
- 正则表达式:正则表达式常用于书写复杂的匹配模式,被广泛应用于Linux和许多相关的开源编程语言.可以再Vi和Perl中使用,且由于其通用性很高,在不同地方出现时,其基本原理都相同.在通用正则表达式中,一些字符是以特殊的方式处理的.
^ 标记行的开头$ 标记行的结尾. 指代单个任意字符[] 括号内包含一个字符范围,其中任一字符均可被匹配例如字符范围a~e在字符范围前使用^表示反向不匹配字符的范围
匹配模式:
[:alnum:] 字母或数字字符
[:alpha:] 字母
[:ascii:] ascii字符
[:blank:] 空格或制表符
[:cntrl:] asfii控制字符
[:digit:] 数字
[:graph:] 非控制非空格字符
[:lower:] 小写字符[:print:] 可打印字符[:punct:] 标点符号字符[:space:] 空白字符包括垂直制表符[:upper:] 大写字母[:xdigit:] 十六进制数字
可以使用如下选项对正则表达式进行扩展的规则表示,如下字符前都需要加\字符进行转义:
? 匹配是可选的,最多匹配1次* 匹配0或多次+ 匹配1或多次{n} 必须匹配n次{n,} 匹配n或n次以上{n,m} 匹配n到m次,包括n和m
应用举例:
$ grep e$ test.txt #匹配以e结尾的行$ grep a[[:blank:]] test.txt #匹配以a结尾的单词$ grep Th.[[:space:]] #匹配以Th开头的三个字母组成的单词$ grep -E [a-z]\{10\} test.txt #匹配10个字符长的小写字母组成的单词
2.3.7 执行结果的获取
我们常常需要捕获命令的执行结果,并暂存在某个变量以待处理、在shell中$(command)语法即表示了command的执行结果,也可以使用`command`反引号,这样得到的是字符串形式的输出结果而不是命令的退出状态。注意要区分环境变量和shell命令,比如pwd是命令而PWD是环境变量,对于变量不需要加圆括号($(pwd)和$PWD)。可以将$(command)的结果直接赋给某个变量暂存起来。如果期望将某条命令的标准输出转换为其他程序的参数则可以使用xargs。
- 算术扩展
我们可以使用expr命令,通过它可以处理一些简单的算术命令,但命令需要调用子shell去执行expr命令,效率很慢,这里可以使用$((expression))扩展来实现算法运算,举例如下:
#!/bin/bashx=0while [ "$x" -ne 10 ]; doecho $xx=$(($x+1))doneexit 0
注意:x=$(command)和x=((expression))是不同的,两对圆括号是用于算术计算和替换,一对圆括号用于获取命令的执行结果。
- 参数扩展
当我们期望在变量名后附加额外的字符形成新字符时,为了保护变量名中内置的其他变量,需要特别注意此时需要将变量用花括号括起来。比如:
i=10echo $i_tmp#出现错误echo ${i}_tmp #正确
在处理多参数扩展时,如下的参数扩展方法可非常精巧的实现相关功能:
${param:-default} 若param为空则设为default值${#param} 给出param长度${param%word} 从param尾部 最小部分${param%%word} 从param的尾部 最长部分${param#word} param的头部 最小部分${param##word} 从param的头部开始删除与word匹配的最长部分,返回剩余内容
应用举例:
#!/bin/bashunset fooecho ${foo:bar}foo=fudecho ${foo:bar}foo=/usr/bin/X11/startxecho ${foo#*/}echo ${foo##*/}foo=/usr/local/etc/local/networksecho $ {foo%local*}echo ${foo%%local*}exit 0
输出结果为:barfudusr/bin/X11/startxstartx/usr/local/etc/usr
${foo:=bar}:foo不存在则赋值为bar否则返回foo的值。${foo:?bar}foo不存在或为空时输出foo:bar并异常终止程序。${foo:+bar}:foo存在且不为空时返回bar。linux下可用cjepg程序将GIF装换为JPEG文件:cjpeg image.gif > image.jpg,如下程序可以实现本路径下的批量处理:
#!/bin/bashfor image in *.gif; docjpeg $image > ${image%%gif}jpgdoneexit 0
2.3.8 here文档
在shell中我们可以向某条命令或程序传递参数,比如:调用Vi启动插入模式,将shell脚本的首行内容从#!/bin/bash改变为#!/bin/sh,这样的完整操作都需要给Vi依照执行顺序传递多个不同参数。此时shell中的here文档就派上了用场。它使传递给命令的参数类似于人们在键盘输入的模式。here文档以<<开始紧跟一个特殊的字符标记序列(常用大写且容易记忆的单词有助于可读性),该序列还需要在结尾处再次出现以标记文档的结束。<<是shell的标签重定向符,在此处,它强制命令的输入是一个here文档。
#!/bin/shcat <<!FUNKY!hellothis is a heredocument!FUNKY!输出结果如下:hellothis is aheredocument
here文档的更常见的用途是输出大量的文本且避免繁复使用echo来输出每一行。在标识符前后使用!!有助于避免混淆。可以通过ed行编辑器来处理文件的多个行,且可以再脚本中直接使用here文档来向它提供命令。
2.3.9 脚本程序的调试
出现错误时,脚本程序一般都会打印错误的行的行号,如果这个错误不明显还可以使用echo命令来显示相关的变量内容,也可以在shell中交互式的输入代码段进行调试。跟踪脚本程序中复杂错误的主要方法是设置各种shell选项,为此可以再调用shell时加上命令行选项或使用set命令。
sh -n <script> set -o noexec(set -n) 只检查语法错误
sh -v <script> set -o verbose(set -v) 命令执行前回显
sh -n <script> set -o xtrace(set -x) 命令处理完前回显
sh -n <script> set -o nounset(set -u) 若使用未定义的变量则给出错误信息
可以使用-o选项开启相关设置,+o选项关闭相关设置.如果期望获取更好的调试效果,可以将xtrace标记(启用或关闭命令跟踪)放在脚本程序问题代码前后,执行跟踪功能,让shell在执行每行语句之前先输出改行并对改行变量进行扩展.可以再shell脚本的开始处添加如下语句,来捕获exit信号并查看退出时的程序状态:
trap 'echo Exiting: critical variable=$critical_variable' EXIT
3、图形化:dialog工具
大部分linux用户都应该见过类似如上的图形界面。这就是用linux下的dialog工具命令输出的简单的图形界面,常用于shell的简单图形编程。部分linux发型版可能是依赖gnome用户接口的gdialog,比如ubuntu。dialog主要用于创建对话框。如下对话框类型:
复选框 --checklist 参数:text height width list-height [tag text status]...
信息框 --infobox 参数:text height width
输入框 --inputbox 参数:text height width [initial string]
菜单框 --menu 参数:text height width menu-height [tag item]...
消息框 --msgbox 参数:text height width
单选框 --radiolist 参数:text height width list-height [tag text status]...
文本框 --textbox 参数:filename text height width
是否框 --yesno 参数:text height width
应用举例:
dialog --title "CheckList" --checklist "Pick Numbers" 15 25 3 1"one""off" 2 "two" "on" 3 "three" "off"
测试结果如下:
(完)。更多内容请参看BLP 4th和Linux shell脚本攻略。