该部分讲述的是shell编程方面的知识,以Bourne Shell为主,因为它是使用最广泛的,因而移植性最好,虽然功能不如现代许多其他版本的shell强大。
篇幅不大,只是一个简明手册,不具备系统性。
1.文件名生成通配符
在shell中,有两种类型的通配符:文件名生成通配符和正则表达式通配符。两者是不同的,注意区分。
字符*
星号*匹配文件名中的任何字符串。
字符?
?匹配文件名中的任何单个字符。
[…]和[!…]
使用[…]匹配方括号中的任何字符。可以使用一个横杠来连接两个字母或数字,表示一个范围。
使用[!…]表示非的意思。
2.正则表达式通配符
(1).基本元字符集
| 元字符 |
含义 |
| ^ |
只匹配行首,在[]中表示否定 |
| $ |
只匹配行尾 |
| * |
一个单字符后紧跟*,匹配0个或多个此字符 |
| [] |
匹配[]内字符,可以是一个单字符,也可以是字符序列,可以使用-表示范围 |
|
用来屏蔽一个元字符的特殊含义 |
| . |
匹配任意单字符 |
| pattern{n} |
用来匹配前面pattern出现次数,n为次数 |
| pattern{n, } |
含义同上,但次数最少为n |
| pattern{n, m} |
含义同上,但次数在n与m之间 |
(2).屏蔽的特殊字符
$ . ‘ “ * [ ] ^ | + ?
(3).例子
| ^$ |
匹配空行 |
| [A-Za-z] |
匹配所有字母 |
| [A-Za-z]* |
匹配所有单词 |
| [^A-Za-z] |
匹配任一非字母型字符 |
| A{2, } |
匹配AAB、AAAB、… |
| [0-9]{2}-[0-9]{2}-[0-9]{4} |
匹配dd-mm-yyyy |
3.find命令
(1).find命令的形式:
find pathname -optino [ -pirnt -exec -ok ]
pahtname:查找的目录路径;
-print:将匹配的文件输出到标准输出;
-exec:对匹配的文件执行给出的shell命令,命令形式为‘command {} ;’,注意空格;
-ok:与-exec类似,在执行前会让用户确认。
(2).-name
按照文件名查找文件。
例:
查找$HOME目录及子目录下所有.txt文件:
find ~ -name "*.txt" -print
查找当前目录及子目录下以一个大写字母开头的文件:
find . -name "[A-Z]*" -print
查找/etc及子目录下以host开头的文件:
find /etc -name "host*" -print
查找$HOME目录及子目录下文件:
find ~ -name "*" -print或find . -print
查找当前目录及子目录下以两个小写字母打头,后跟两个数字,最后是.txt后缀的文件:
find . -name "[a-z][a-z][0-9][0-9].txt" -print
(3).-perm
按照权限查找。
例:
查找当前目录及子目录下权限为755的文件:
find . -perm 755 -print
查找当前目录及子目录下所有用户都可读、写、执行的文件(使用八进制数字前要加-):
find . -perm -007 -print
(4).-prune
忽略某个目录,如果同时使用了-depth,则-prune被忽略。
例:
find /apps -name "/apps/bin" -prune -o -print
(5).-user和-nouser
-user:按照文件属主查找;
-nouser:查找文件属主帐户已经被删除的文件。
例:
查找属主为duan的文件:
find ~ -user duan -print
查找文件属主帐户已经被删除的文件
find /home -nouser -print
(6).-group和-nogroup
-group:按照文件所属的组查找;
-nogroup:查找属于不存在的组的文件。
例:
查找属于用户组informix的文件
find /apps -group informix -print
查找不存在组的文件:
find / -nogroup -print
(7).-mtime
按更改时间查找,减号-限定更改时间距今n日内的文件,加号+限定更改时间距今n日外的文件。
例:
查找更改时间在5日内的文件:
find . -mtime -5 -print
查找更改时间在3日前的文件:
find . -mtime +3 -print
(8).-newer
查找更改时间新的文件,可以使用!逻辑非。
例:
查找比haha.txt新的文件:
find . -newer haha.txt
查找比haha.txt新但比find.txt旧的文件:
find . -newer haha.txt ! -newer find.txt -print
(9).-type
按类型查找。类型有:
- b,块设备文件;
- d:目录;
- c:字符设备文件;
- p:管道文件;
- l:符号链接文件;
- f:普通文件。
例:
查找目录文件:
find /etc -type d -print
查找非目录文件:
find . ! -type d -print
查找符号联接文件:
find /etc -type l -print
(10).-size
按照文件大小查找。单位是块,也可以是字节(后跟c)。
例:
查找字节大于1M的文件:
find . -size +1000000c -print
查找字节为100的文件:
find . -size 100c -print
查找大小大于10块的文件:
find . -size +10 -print
查找字节小于10的文件:
find . -size -10c -print
(11).-depth
先匹配所有文件,再在子目录中查找。
例:
先匹配当前目录中所有.txt文件,再在子目录中找:
find . -name "*.txt" -depth -print
(12).-mount
只在当前文件系统中查找,不进入其他文件系统。
例:
find . -name "*.txt" -mount -print
(13).-cpio
使用cpio命令将文件备份到磁带上。
例:
find etc home apps -depth -print -cpio /dev/rmt0
(14).-exec和-ok
对匹配的文件执行某操作。
例:
find logs -type f -mtime +5 -exec rm {} ;find . -name "*.log" -mtime +5 -ok rm {} ;find /etc -name "passwd*" -exec grep "rounder" {} ;
(15).和xargs结合使用
find . -name "*.txt -print |xargx filefind . -name "*.txt" -print | xagrs echo >/tmp/tmpfilefind . -perm -7 -print |xargs chmod o-wfind . -type f -print |xargs grep "device"find . -name * -type f -print |xargs grep "DBO"
4.shell输入和输出
(1).echo命令
显示文本行或变量,缺省会自动换行。
特殊字符:
有些系统使用echo的-n选项来控制不换行。
特殊字符使用来转义,如双引号。
(2).read命令
read命令从标准输入读入一行信息,并将其赋给变量。如果只有一个变量,则整行内容都赋给此变量,若有多个变量,则把输入内容按空格分开分别赋给变量,多余的输入内容全部赋给最后一个变量。
read形式为:
read var1 var2 …
(3).cat命令
cat命令显示文件内容,使用选项-v可以显示控制字符。
如:
cat myfilecat -v myfile
(4).tee命令
tee命令把输出的一个副本送到标准输出,另一个副本拷贝到相应的文件中。
如:
who | tee who.out;who | tee -a who.out;-a表示追加到文件末尾。
(5).文件重定向
文件描述符0为标准输入,文件描述符1为标准输出,文件描述符2为标准错误。
常用重定向命令:
command >filename:把标准输出重定向到一个新文件中;command >>filename:把标准输出重定向到一个文件(附加);command 1>filename:把标准输出重定向到一个新文件中;command >filename 2>&1:把标准输出和标准出错重定向到一个文件中;command 2>filename:把标准错误重定向到一个新文件中;command 2>>filename:把标准错误重定向到一个文件(附加);command >>filename 2>&1:把标准输出和标准出错重定向到一个文件中(附加);command < file >file2:以file为标准输入,以file2为标准输出;command < filename:以filename为标准输入;command << delimiter:从标准输入读入,直到遇到delimiter分界符;command <&m:把文件描述符m作为标准输入;command >&m:把标准输出重定向到文件描述符m中;command <&-:关闭标准输入。
(6).exec命令
exec命令替换当前shell,它践踏了你当前的shell。
一个例外是exec对文件描述符操作时,它不覆盖当前shell。
使用exec操作文件描述符,例如:
exec 4<&0 0<stock.txt;
把描述符4重定向到标准输入,把标准输入重定向到stock.txt。
exec 0<&4;
把描述符0重定向到描述符4,即恢复标准输入。
5.命令执行顺序
(1).使用&&
一般形式为:
命令1&& 命令2
含义:&&左边的命令(命令1)返回真(即返回0,成功被执行)后,&&右边的命令(命令2)才能够被执行。
如:
cp justice.doc justice.bak && echo "cp was OK"
(2).使用||
一般形式为:
命令1|| 命令2
含义:如果左边的命令(命令1)未执行成功,那么就执行||右边的命令(命令2)。
如:
cp wopper.txt oops.txt || echo "cp failed"
(3).使用()和{}组合命令
在当前shell执行一组命令,形式为:
(命令1;命令2;…)
在子shell中执行一组命令,形式为:
{命令1;命令2;…}
如:
comet month_end || (echo "hello" | mail dave; exit)
6.stty命令
stty用于设置终端特性。
(1).查询现有终端设置
stty -a
(2).设置tty选项
stty name character
如:
stty erase ^H
在vi中输入控制字符:先按ctrl-v,再按该控制字符。
(3).保存stty现有设置
stty -g
以可读形式保存stty现有设置,便于以后恢复。
如:
SAVETTY=`stty -g`...stty $SAVETTY
7.shell变量
(1).设置变量
- Variable_name = value,设置实际值到变量中;
- Variable_name + value,如果设置了变量,则使用value值,但不改变量的值;
- Variable_name
value,如果未设置变量,显示用户错误信息value;
- Variable_name ? value,如果未设置变量,显示系统错误信息;
- Variable_name := value,如果设置了变量,则使用它,如果未设置变量,设置其值;
- Variable_name :- value,同上,但取值并不设置到变量中。
如:
echo "The file is ${FILES:?}"echo "The file is ${FILES:?' sorry cannot locate the files'}"
COLOUR=blueecho "The sky is ${COLOUR:-grey} today"
(2).显示变量
在变量名前加$,可以用{}将变量名括起来。如:
echo ${CREAT_PICTURE}
(3).清除变量
使用unset命令清除变量。
(4).显示所有本地shell变量
使用set命令。
(5).设置只读变量
variable_name=valuereadonly variable_name
(6).查看所有只读变量
使用readonly命令。
(7).位置变量参数
传给脚本的参数可以使用如下变量进行访问,只有前9个可以直接访问,使用shift可以改变此限制:
$0、$1、$2、…、$9
其中$0为脚本名字,$1到$9为第一到第九个参数。
(8).特定变量参数
$#:传递到脚本的参数个数;
$*:以一个单字符串显示所有向脚本传递的参数;
$$:脚本运行的当前进程ID号;
$!:后台运行的最后一个进程的进程ID号;
$@:与$#类似;
$-:显示shell使用的当前选项,与set命令相同;
$?:显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误。
8.环境变量
(1).设置环境变量
variable_name=value; export variable_name或variable_name=valueexport variable_name
(2).查看所有环境变量
使用env命令。
(3).环境变量列表
CDPATH;EXINIT;HOME;IFS;LOGNAME;MAIL;MAILCHECK;MAILPATH;PATH;PS1;PS2;SHELL;TERMINFO;TERM;TZ;EDITOR;PWD;PAGER;MANPATH;LPDEST/PRINTER。
9.引用
shell引用类型有:””双引号;’’单引号;`反引号;反斜线。
(1).双引号
双引号可引用除字符$、`、外的任意字符或字符串,这几个特殊字符是美元符号、反引号和反斜线,对shell来说,它们有特殊意义。
(2).单引号
类似于双引号,但shell会忽略任何引用值。
(3).反引号
反引号用于设置系统命令的输出到变量,shell将反引号的内容作为一个系统命令,并执行其内容。
(4).反斜线
反斜线屏蔽下一个字符的特殊含义。
具有特殊含义的字符:& * + ^ $ ` “ | ?。
如:
echo $$ 显示当前进程ID号;echo $$ 显示$$;expr 12 * 12 计算12乘以12;echo “This is a copyright 251 sign” 显示八进制字符;
10.条件测试
(1).语法
使用test命令,形式如下:
test condition或[ condition ] (在括号和条件之间要有空格)
测试结果为0表示成功,其他为失败。
(2).逻辑操作符
-a 逻辑与,操作符两边都为真,结果为真,否则为假;
-o 逻辑或,操作符一边为真,结果为真,否则为假;
! 逻辑否,条件为假,结果为真。
(3).测试文件状态
-d 目录-f 正规文件-L 符号连接-r 可读-s 文件长度大于0、非空-w 可写-u 文件有suid位设置-x 可执行
如:
test -w score.txt[ -d appbin ][ -w b1.txt -a -w b2.txt ]
(4).字符串测试
字符串测试有5种格式:
test "string"test string_operator "string"test "string" string_operator "string"[ string_operator string ][ string string_operator string ]
其中string_operator可为:
= 两个字符串相等;
!= 两个字符串不等;
-z 空串;
-n 非空串。
如:
[ -z $EDITOR ][ $EDITOR = "vi" ][ "$TAPE1" = "$TAPE2" ][ "$TAPE1" != "$TAPE2" ]
(5).数值测试
格式如下:
"number" number_operator "number" or[ "number" number_operator "number" ]
其中numbe_operator可为:
-eq 数值相等;
-ne 数值不等;
-gt 第一个数大于第二个数;
-lt 第一个数小于第二个数;
-le 第一个数小于等于第二个数;
-ge 第一个数大于等于第二个数。
如:
[ "$NUMBER" -eq "300" ][ "$NUMBER" -gt "300" ][ "$NUMBER" -gt "$SOURE_COUNT" ][ "99" -le "993" ]
(6).expr用法
expr命令一般用于数值计算,但也可用于字符串。格式如下:
expr argument operator argument
如:
expr 10 + 10expr 30 / 3expr 30 / 3 / 2expr 30 * 3 乘法要用反斜线LOOP=0LOOP=`expr $LOOP + 1`
可以用expr测试一个数,如果试图计算非整数,将返回错误:
$VALUE=helloexpr $VALUE + 10 >/dev/null 2>&1echo $? (失败)
expr还能比较字符串和进行模式匹配。expr的返回值成功为1,与系统的最后退出命令结果刚好相反,不要混淆。
11.控制流结构
(1).退出状态
退出shell使用如下命令:
exit n
其中n为退出状态,0表示成功,1表示失败。
(2).if then else语句
格式为:
if condition1then (if和then不在同一行) ....elif condition2then ....else ....fi或:if condition; then (if和then在一行时要用分号) ....fi
例如:
if [ “10” -le “12” ]then …fiif grep david ha.txt >/dev/null 2>&1then …fi
(3).交互模式
测试脚本是交互模式还是非交互模式,使用test的-t选项,若测试成功,则为交互方式。如:
if [ -t ]; then echo “we are interactive with a terminal”fi
(4).空语句
if语句各部分都不能为空,可以使用空命令解决这个问题。
空语句形式为一个冒号:。
if [ -z $DIR ]then echo “DIR is empty”else : #do nothingfi
(5).case语句
case语句格式:
case 值 in模式1) 命令1 … ;;模式2) 命令2 … ;;esac
模式:
模式可以使用元字符:* ? [ ... ]。
模式中可以使用“|”作为或命令。
示例:
case $TERMINAL invt100|vt102) TERM=vt100 ;;vt200) TERM=vt200 ;;*) echo “not valid” exit 1 ;;esac
(6).for循环
for语句格式:
for 变量名 in 列表do 命令1 命令2 …done
列表:
省略in列表时,for接收命令行位置参数作为参数,等同于:
for param in “$@”或for param in “$*”
示例:
for loop in 1 2 3 4 5for loop in “orange red blue grey”for loop in `ls`
(7).until循环
until循环执行一系列命令直至条件为真停止。
until格式:
until 条件 命令1 …done
条件测试发生在循环末尾,因此循环至少执行一次。
(8).while循环
while循环格式:
while 命令do 命令1 命令2 ..done
永真循环:
while :do …done
(9).使用break和continue
break允许跳出循环或case语句。如果在一个嵌套循环里,可以指定跳出的循环个数。如在两层循环里,用break 2刚好跳出整个循环。
continue跳过当前循环步,继续下一循环。
12.shell函数
(1).函数定义格式
function 函数名(){ 命令1 …}
(2).函数参数
函数里使用参数就象在一般脚本中使用特殊变量$1、$2等一样。
(3).函数返回
函数结束可以用return返回函数执行结果:
return 从函数返回,用最后状态命令决定返回值;return 0 无错误返回;return 1 有错误返回。
(4).函数返回值测试
在脚本调用函数语句的后面使用最后状态命令测试函数的返回值。如:
check_is_directory $FILENAMEif [ “$?” = “0” ]then …fi
更好的方法是在if中测试。如:
if check_is_directory $FILENAMEthen …fi
(5).函数文件
文件的首行为#!/bin/sh。
装入函数文件格式:
. /pathname/filename
在shell中装入后,可以用set命令查看,用unset删除。
在脚本中装入后,可以在脚本中使用定义的函数。
13.脚本参数
(1).处理方式
脚本处理参数有三种方式:
- 使用特定变量$1、$2、…、$9,$#统计参数个数。此法的缺点是只能处理9个参数;
- 使用shift;
- 使用getopts。
(2).shift
shift的功能是每次将参数位置向左偏移一位,通过循环可以处理所有的参数。
如:
while [ $# -ne 0 ]do echo $1 shiftdone
(3).获得命令行输入的最后一个参数
有两种方法:
- 使用命令:eval echo $$#;
- 使用命令:shift `expr $#-2`。
(4).getopts
使用getopts可以处理复杂的命令行参数。
getopts的一般格式为:
getopts option_string variable