SHELL复习摘要(二)
getopts命令
通过getopts可以更加容易的控制多个命令行参数。
一般格式:getopts option+string variable
while getopts ahfv OPTION
这里while循环读取命令行,option_string为指定的5个选项(-a、-h、-f、-v),脚本中variable为OPTION。注意这里并没用用连字符指定每个单个选项。getopts读取option_string,获知脚本中使用了有效选项。getopts接收完所有参数后,返回非零状态,意即参数传递成功,变量OPTION保存最后处理参数。
getopts命令简化了选项处理。它能理解POSIX选项中将多个选项字母组织到一起的用法,也可以用来遍历整个命令行参数,一次一个参数。getopts的第一个参数使列出合法选项字母的一个字符串。如果选项字母后跟着冒号,则表示该选项需要一个参数,此参数是必须提供的。一旦遇到这样的选项,getopts会放置参数值到变量OPTARG中。另一个变量OPTIND包含下一个要处理的参数的索引值。shell会把该变量初始化为1。getopts的第二个参数为变量名称,在每次getopts调用时,该变量会被更新;它的值是找到的选项字母。当getopts找到不合法的选项时,它会将此变量设置为一个问号字符。将冒号置于选项字符串中作为第一个字符,可以使得getopts以两种方式改变它的行为:首先,它不会显示任何错误信息;第二,除了将变量设置为问号之外,OPTARG还包含给定的不合法选项字母。
例如:
#设置标志变量为空
file= verbose= quiet= long=
#开头的冒号,是我们处理错误的方式
while getopts :f:vql opt
do
case $opt in
f) file=$OPTARG
;;
v) verbose=true
quiet=
;;
q) quiet=true
verbose=
;;
l) long=true
;;
‘?’) echo “$0: invalied option -$OPTARG”>&2
echo “Usage:$0 [-f file] [-vql] [files…]”>&2
exit 1
;;
esac
done
shift $((OPTIND - 1)) #删除选项,留下参数
有时候有必要再脚本中指定命令行选项取值。getopts为此提供了一种方式,即在option_string中将一个冒号放在选项后。例如:
getopts ahfvc: OPTION
上面一行脚本指出,选项a、h、f、v可以不加实际值进行传递,而选项c必须取值。使用选项取值时,必须使用变量OPTARG保存该值。如果试图不传值给该选项,会返回一个错误信息。将冒号放在option_string开始部分。如:
while getopts :ahfvc: OPTION
在case语句里使用?创建一可用语句捕获错误。
case
\?)echo “`basename $0` -[a h f v] –[c value] file”
;;
Esac
函数
函数(function)是指一段单独的程序代码,用以执行一些定义完整的单项工作。
function_name () {
command
return number
}
return语句会返回函数的退出值给调用它的脚本,在函数中使用exit会终止整个脚本。
read
-p会打印后面的readline内容。例如:read -p “Enter:” i
-r 会忽略读取内容中的特殊字符如\。
额外的重定向运算符
set -C POSIX shell提供了防止文件被意外截断的选项。执行set -C后,使用>重定向遇到目标文件已存在时,就会失败。>|则会令set -C失效。
提供行内输入(inline input)的<<与<<-:使用program<<delimiter,可以在shell脚本正文内提供输入数据。这样的数据叫作嵌入文件(here document)。默认情况下,shell可以在嵌入文件正文内做变量,命令和算术替换:如果定界符以任何一种形式引号括起来,shell则不会处理输入的内文。
嵌入文件重定器的第二种形式有一个负号。这种情况下,所有开头的制表符在传递给程序作输入之前,都从嵌入文件与结束定界符中删除。
以<>打开一个文件作为输入与输出之用:使用program<>file,可供读取和写入操作。默认是在标准输入上打开file。一般来说,<以只读模式打开文件,而>以只写模式打开文件。<>运算符则是以读取与写入两种模式打开给定的文件。这交由program确定并充分利用;实际上,使用这个操作符并不需要太多的支持。
文件描述符处理
在系统内部,UNIX是以一个小的整数数字,称为文件描述符,表示每个进程的打开文件。传统上shell允许你直接处理至多10个打开文件:从0~9。POSIX将大于9的文件描述符,保留给各实现自行定义。Ksh除外。
文件描述服0,1和2分别对应标准输入,标准输出和标准错误输出。
exec命令可以用来改变shell本身I/O设置。
exec 2>/tmp/$0.log 重定向shell本身的标准错误输出
exec 3</tmp/file 打开信文件描述符3
read name rank serno <&3 从该文件描述符3读取
如果你希望取消标准错误输出的重定向,可以先把它复制到一个新的文件以存储文件描述符。例:
exec 5>&2 把原来的标准错误输出保存到文件描述符5上
exec 2>/tmp/$0.log 重定向标准错误输出
... 执行各种操作
exec 5>&2 将原始文件复制到文件描述符2
exec 5>&- 关闭文件描述府5,因为不再需要了
exec为单向操作。控制权不可能会回到脚本。
波浪号展开与通配符
shell有两种与文件名相关的展开。第一个是波浪号展开,另一个称之为通配符展开或者全局展开或者路径展开。
波浪号展开
如果命令行字符串的第一个字符为波浪号或者便来那个指定的值里任何未被引号括起来的冒号之后的第一个字符为波浪号时,shell便会执行波浪号展开。好处:1.它是一种简洁的概念表示方式,让查阅shell脚本的人更清除脚本在做的事。2.它可以避免在程序里把路径名称直接编码。
例:
read user
vi /home/$user/.profile
read user
vi ~$user/.profile #是shell在系统的密码数据库里,寻找用户,在将~$user替换成$user。
如果有任何变动,用户的子目录位置变迁,那么第一个代码就需要重写,但是第二个就避免了重写的情况。
通配符展开
基本通配符
? 任何单一字符
*任何字符和字符串
[set] 任何在set里的字符
[!set] 任何不在set里的字符
例如:
[,.;] 逗号、句号或者分号
[-_] 破折号或者下划线
命令替换
命令替换指shell执行命令并将命令替换部分替换为执行该命令后的结果。命令替换有2个形式:
1. 使用反引号(也称为重音符号)。
echo outer `echo inner1 \`echo inner2\` inner1` outer
内嵌反引号时候需要用\转义
2. 使用$(),推荐容易理解。
echo outer $(echo inner1 $(echo inner2) inner1) outer
内嵌双引号无需转义
引用
引用是用来防止shell将某些你想要的东西解释成不同的意义。
反斜杠转义:字符前置反斜杠
单引号:单引号强制shell将一对引号之间的所有字符都看成其字面上的意义。单引号被括在双引号里时候就无特殊意义了。
双引号:双引号就像单引号那样,将括起来的文字视为单一字符串。不过双引号会确切的处理括起来的文字中的转义字符和变量、算术、命令替换。
使用单引号的时机是你希望完全不处理的地方。否则,当你希望将多个单词视为单一字符串,但又需要shell为你做些事情的时候,请使用双引号。
shell命令执行顺序
1. 按照固定的一组meta字符来将命令分割成token,有空格、制表符、换行符、分号、逗号、<、>、|、&。
2. 检查第一个单词是否是关键字。
3. 检查第一个单词是否是别名。
4. 检查所有单词是否需要波浪号展开。
5. 检查是否有变量展开。
6. 检查是否有命令替换。
7. 执行算术替换。
8. 检查是否有$IFS字符。
9. 通配符展开。
eval语句
eval语句是在告诉shell取出eval的参数,并再执行它们一次,使它们经过整个命令行的处理步骤。
因为变量展开在后,展开后|和more就变成ls的参数了。
使用eval后会把展开后的ls 、|和more重新送入shell,通过|分割为2个命令,从而返回正确结果。
subShell与代码块
subShell是一群被括在圆括号里的命令,这些命令会在另外的进程中执行。
tar –cf - . | (cd ../;tar –xpf -)
代码块概念上与subShell雷同,只不过它不会建立新进程。代码块里的命令以花括号括起来,且对主脚本的状态会造成影响。
cd /some/directory || {echo could not change to /some/directory! >&2;exit 1}
subShell和代码块区别:
结构 定界符 认可的位置 另外的进程
subShell () 行上的任何位置 是
代码块 {} 在换行字符、分号或者关键字之后 否
脚本范例
AWK
awk里一般常用到的内建标量变量
FILENAME 当前输入文件的名称
FNR 当前输入文件的记录数
FS 字段分隔字符(正则表达式)默认为:” “
NF 当前记录的字段数
NR 在工作中的记录数
OFS 输出字段分隔字符(默认为:” “)
ORS 输出记录分隔字符(默认为:”\n”)
RS 输入记录分隔字符(仅用于gawk与mawk里的正则表达式)默认为:”\n”
trap命令
trap命令用于指定在接收到信号后将要采取的行动。
trap命令的一种常见用途是在脚本程序被中断时完成清理工作。历史上,shell总是用数字来代表信号,而新的脚本程序应该使用信号的名字。你可以在命令提示符下输入命令trap -l来查看信号编号及其关联的名称,在使用信号名时需要省略SIG前缀。
trap命令的参数分为两部分,前一部分是接收到指定信号时将要采取的行动,后一部分是要处理的信号名。
trap command signal
如果要重置某个信号的处理条件到其默认值,只需简单的将command设置为-。如果要忽略某个信号,就把command设置为空字符串‘’。一个不带参数的trap命令将列出当前设置的信号及其行动的清单。
注意:对于类似INT的信号,如果捕获后,在trap设置的命令中不提供退出机制,程序将无法通过 Ctl+C 停止。
X/Open规范里面规定的能够被捕获的比较重要的一些信号(括号里面的数字是传统的信号编号):
信 号 |
说 明 |
HUP(1) |
挂起,通常因终端掉线或用户退出而引发 |
INT(2) |
中断,通常因按下Ctrl+C组合键而引发 |
QUIT(3) |
退出,通常因按下Ctrl+\组合键而引发 |
ABRT(6) |
中止,通常因某些严重的执行错误而引发 |
ALRM(14) |
报警,通常用来处理超时 |
TERM(15) |
终止,通常在系统关机时发送 |
例如:
trap ‘exit 1’ HUP INT QUIT PIPE TERM
trap ‘rm –rf $tmpfile’EXIT
cmp
用途:
比较两个文件的内容并报告不同的第一个字符。
补充说明:当相互比较的两个文件完全一样时,则该指令不会显示任何信息。若发现有所差异,预设会标示出第一个不同之处的字符和列数编号。若不指定任何文件名称或是所给予的文件名为”-”,则cmp指令会从标准输入设备读取数据。
参数:
-c或–print-chars 除了标明差异处的十进制字码之外,一并显示该字符所对应字符。
-i<字符数目>或–ignore-initial=<字符数目> 指定一个数目。
-l或–verbose 标示出所有不一样的地方。
-s或–quiet或–silent 不显示错误信息。
-v或–version 显示版本信息。
–help 在线帮助。
cmp –s a.txt b.txt