250 likes | 608 Views
SHELL 脚本编程. 林怀东 2005-3-12 linhuaidong@mprc.pku.edu.cn. Outline. Shell 脚本简介 常用 shell 命令 Shell 常用变量 流程控制 Shell 函数. shell 脚本介绍. 一个 shell 脚本可以包含一个或多个 shell 命令,可用来自动完成通常在命令行上执行的重复循环或者复杂的工作,节省大量时间,且功能强大 shell 脚本主要内容 脚本按行解释执行,每一行可 以是命令、注解、或是流程控制指令等
E N D
SHELL脚本编程 林怀东 2005-3-12 linhuaidong@mprc.pku.edu.cn
Outline • Shell脚本简介 • 常用shell命令 • Shell常用变量 • 流程控制 • Shell函数
shell 脚本介绍 一个shell 脚本可以包含一个或多个shell命令,可用来自动完成通常在命令行上执行的重复循环或者复杂的工作,节省大量时间,且功能强大 shell脚本主要内容 • 脚本按行解释执行,每一行可 以是命令、注解、或是流程控制指令等 • 脚本第一行以 #! 开始,后面加所使用的shell(需指明整个路径名称) (如:以 #!/bin/sh指定使用Bourne Shell) • 在脚本中执行一个命令的方法和在命令行中相同,可以前台或后台执行,也可设定一些环境变量 • 注释,#后面的同一行文字为注释,解释器对此不予解释 • 脚本的流程控制近似于一般高级语言,这使得脚本的功能比DOS的批处理文件功能更加强大
常用shell命令 • 文件及文件属性操作 • ls、cp、mv、rm • ln、ln –s、chmod、chown、chgrp • 输入输出操作 • echo 、cat • >>、>、<<、| • 标准输入 0 、标准输出 1 、 标准错误输出 2 • 目录操作 • cd、 pwd、 ls dir • mkdir、 cp、 mv 、 rmdir、 rm -r • 文本过滤 • Head、 tail、 grep、sort、 uniq • sed、 awk • 其他 • find、expr • 获取信息: man
正则表达式——sed与awk的基础 • 正则表达式是一些特殊或不很特殊的字符串模式的集合。 • 字符集包括:普通字符集和元字符集(通配符) • 普通字符集:大小写字母、数字、空格、下划线 • ^ 行首 • $ 行尾 • * 一个单字符后紧跟*,匹配0个或多个此单字符 • [ ] 匹配[ ]内字符,可以是一个单字符,也可以是字符序列。 可以使用”-“来表示[ ]内范围,如[1-5]等价于[1,2,3,4,5]。 • \ 屏蔽一个元字符的特殊含义,如\$表示字符$,而不表示匹配行尾。 • . 匹配任意单字符 • 几个常见的例子: • 显示可执行的文件:ls –l | grep …x...x..x • 只显示文件夹:ls –l | grep ^d • 匹配所有的空行:^$ • 匹配所有的单词:[A-Z a-z]* • 匹配任一非字母型字符:[^A-Z a-z] • 包含八个字符的行:^……..$(8个.)
Sed命令 • 命令格式 • sed ‘/pattern/ action’ files • pattern: 正则表达式 • action: 操作,包括p、d、s • 示例: • 打印行:sed –n ‘/ 0\.[0-9][0-9]$/p’ fruit_prices.txt • 删除行:sed ‘/^[Mm]ango/d’ fruit_prices.txt • 执行替换/pattern1/s/pattern2/pattern3/g: sed ‘s/paech/peach/g fruit_prices.txt’ • 使用多重sed sed –e ‘cmd1’……-e ’cmdN’ files: sed –e ‘s/paech/peach/’ –e ‘s/ *[0-9][0-9]\.[0-9][0-9]$/\$/’ fruit_prices.txt • 在管道中使用sed
awk命令 • 命令格式 • awk ‘/pattern/ {actions}’ files • 示例: • 字段编辑:awk –F: ‘{ print $1,$3}’ inputfiles 或:awk –F: ‘{ printf “%s is %s\n”,$1,$3}’ inputfiles • 执行指定模式的操作: awk ‘/ *\$[1-9][0-9]*\.[0-9][0-9] */ {print $0; next} /*\$0\.[0-9][0-9] */ {print $0}’ fruit_prices.txt • 比较操作符:<、>、<=、>=、==、!=、value ~ /pattern/、value !~ /pattern/ (相关:&&、||) awk ‘($2 ~ /^\$[1-9][0-9]*\.[0-9][0-9]$/) && ($3 < 75)’ { printf “……”}’ input_f • 利用管道符将标准输入作为输入
shell变量 为使shell编程更加容易而且有效,系统提供了一系列shell变量,可以保存诸如文件名、路径名等有用信息,使系统获知用户相关设置 • 本地变量:在用户现在的shell生命期的脚本中使用,若shell启动另一个进程或退出,该变量值无效 • 环境变量:用于所有用户进程(子进程),环境变量可以在命令行中设置,但用户注销时变量值丢失。可将此变量放入.profile文件中使每次登录使这些值都被初始化 • 特定变量参数 • 位置变量参数
本地变量 • 命名:可以任何不包含空白字元的字串来当做变量名称 • 设置:v-name=value或 {v-name=value}其中, =:设置实际值到v-name; +:若已设置v-name,重设其值 ?:若未设置v-name,报错;:-:若未设置v-name,设置新 • 显示:echo可以显示单个变量取值(变量使用时名字前加$) • 清除:可用unset命令清除变量,即:unset v-name • 查看所有本地变量:可用set命令显示所有本地定义的变量 • 只读变量:在设值变量后加命令:readonly v-name, 即 将变量设为只读方式,任何人试图改变它均返回错误信息, 用readonly命令可察看所有只读变量
环境变量 环境变量的设置和使用基本与本地变量相同,除了 • 环境变量设置时必须用export导出,其格式为 V-NAME=value; export V-NAME (或舍去分号,分写成两行) • 查看所有环境变量使用env命令 常用预留环境变量 • EDITOR设置编辑器,如:EDITOR=vi; export EDITOR • PWD 当前路径名 • MANPATH保存系统上man文本目录,目录间用冒号分隔,如 MANPATH=/usr/apps/man:/usr/local/man;export MANPATH
特定变量参数&位置变量参数 有些变量用以表示脚本运行时的一些相关信息,这些变量一开始执行脚本时就会设定,并且不能被修改,被称作特定变量参数。如: • $0 当前脚本的文件名 • $# 当前脚本的参数个数 • $*以一个单字符串显示所有向脚本传递的参数 • $$ 脚本运行的当前进程PID • $!后台运行的最后一个进程的PID • $?显示最后命令的退出状态。0表示没有错误,其他任何值均表 明有错误 • 位置变量参数可以完成向一个shell脚本传递信息的功能,位置参数可任意多,但只有前9个被访问,以$n表示当前脚本的第n个参数值,其中n=1..9
变量引用 在脚本中执行变量替换时最容易犯的错误就是由于引用错误。为防止引用时产生误解,shell有一下引用类型 双引号“”:可引用除$、`、\外任意字符或字符串,最好在反馈文本字符串时全使用双引号 单引号‘’:可引用引号里所有字符(包括引号) $ A=‘a’ $ echo $A输出结果为 a $ echo “$A”输出结果为 a $ echo ‘$A’输出结果为 $A 反引号``:设置系统命令输出到变量,shell将反引号内作为一个系统命令并执行 $ echo `date`输出系统时间 $ echo date输出结果为date 反斜线\ :屏蔽其下一字符的特殊含义(& * + ^ $ ` “ | ? ) $echo *打印当前整个目录列表$ echo \*输出结果为 *
流程控制 shell提供了用来控制程序执行流程的命令,用户可以用这些命令建立非常复杂的程序。 与传统语言不同的是,shell用于指定条件值的不是布尔表达式而是命令和字符串 控制流程包括: • 条件测试 • 循环结构
条件测试(1) test命令: test condition或[ condition ] 用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试,其测试符和相应的功能分别如下: • 数值测试:–eq:相等 –ge:数1大于等于数2 –gt:数1大于数2–ne:不相等 –le:数1小于等于数2 –lt:数1小于数2 • 字符串测试:=:相等 !=:不相等 –z 字符串:空串 –n 字符串:非空串 • 文件状态测试:-e 文件名:文件存在 -r 文件名:文件存在且可读-w 文件名:文件存在且可写 -x 文件名:文件存在且可执行-s 文件名:文件存在且非空 -d 文件名:文件存在且为目录-f 文件名:文件存在且为普通文件 • 逻辑操作符 shell提供了与(“-a”)、或(“-o”)、非(“!”)三个逻辑操作符用于将测试条件连接起来,其优先级为:“!”最高,“-a”次之,“-o”最低
条件测试(2) shell脚本中的条件分支是通过if条件语句来实现,其格式为 if 条件命令串1 then 条件1为真时的命令串 elif 条件命令串2 then 条件1为假、条件2为真时的命令串 else 条件1、2均为假时的命令 fi 例:文件拷贝输出检查ifcp #!/bin/sh # ifcp if cp myfile myfile.bak then echo “Good copy” else echo “`basename $0`:error” fi 其中if语句必须以 fi 终止 elif 和 else 部分可省略 也可有多个 elif部分 if语句各部分不能为空 但可使用永远为真的空命令 “:”解决此问题 • 运行结果: • 从myfile到myfile.bak到文件拷贝正常 • $ sh ifcp • Good copy • cp命令没有完成拷贝 • $ sh ifcp • ifcp :error
条件测试(3) • if条件语句用于在两个选项中选定一项,而case条件选择为用户提供了根据字符串或变量的值从多个选项中选择一项的方法 , 其格式为:case 值in 模式1) 若干命令行1;;模式2) 若干命令行2;;……*) 其他命令行esac • 模式部分可能包括元字符 *任意字符? 任意单字符 [..]类或范围中任意字符 取值后面的单词必须为in; 每个模式必须以“)”结束; 取值可为变量或常数; 取值将检查匹配的每个模式,一旦匹配,将执行期间所有命令直至“;;”,之后不再继续其他模式,若无一匹配,使用 * 捕获该值
条件测试(3续) 执行结果: $ sh yorn Do you wish to proceed:ab yorn:Unkown $ sh yorn Do you wish to proceed:y yes is selected 注: echo –n :输出结束时不换行 read ANS:从标准输入设备读入并赋 值给本地变量ANS exit 0:退出shell程序,其后数字为 返回状态,0为成功,1为错误 例:提示y或n #!/bin/sh #yorn echo –n “Do you wish to proceed:” read ANS case $ANS in y|Y|yes|Yes) echo “yes is selected” ;; n|N) echo “no is selected” exit 0 ;; *) echo “`basename $0` :Unkown” exit 1 ;; esac
循环结构(1) for循环对一个变量所有可能的值都执行一个命令序列。一般格式为: for 变量名[in 数值列表]do 若干命令行done 例1:循环备份 #!/bin/sh #forcp BAK=“.bak” for loop in `ls` do echo “copy $loop to $loop$BAK” cp $loop $loop$BAK done 执行结果 $ sh forcp copy a to a.bak copy b to b.bak 假设变量名是var,则数值列表给出的数值将顺序替换循环命令列表中的$var。若省略in,则变量var的取值为位置参数。对变量的每一个可能的赋值都将执行do和done之间的命令列表 例2:使用参数 #!/bin/sh #forparam for param do echo “$param” done 执行结果 $ sh forparam Hello Kitty Hello Kitty
循环结构(2) while 和 until均用命令的返回状态值来控制循环,格式分别为: while 若干命令行1 do 若干命令行2 done 例:循环输出 #!/bin/sh # whileread NUM=0 echo –n “enter: ” while [ $NUM –lt 5 ] do NUM=`expr $NUM + 1` echo –n “$NUM ” done until 若干命令行1 do 若干命令行2 done until和while的区别在于:while循环在条件为真时继续执行,而until在条件为假时继续执行 只要命令行1最后一个命令的返回状态为真,就继续执行do...done之间的“命令行2” 执行结果 $ sh whileread 1 2 3 4 5 注: expr :整数(字符串)的计算 expr argument operator argument 其中乘号必须用“/”屏蔽其特定含义
循环结构(3) • break :立即终止当前循环的执行,跳出循环。若在嵌入循环中,可指定跳出的循环个数 • contiune:不跳出循环,仅是不执行本次循环后面的语句而立即开始下一次循环的执行 • 这两个语句只有放在do和done之间才有效 例:跳出case死循环 脚本一直循环直到输入大于3 #!/bin/sh # breakout # : 即空命令 while : do echo –n “Enter the number” read ANS case $ANS in 1|2|3) echo –n “$ANS ” ;; *) echo “wrong” break ;; esac done
shell函数 • 在shell中还可以将一组命令集或语句组成一个可用块,即shell函数。它与shell程序形式上是相似的,不同的是它不是一个单独的进程,而是shell程序的一部分 • 函数定义的基本格式为:[function] 函数名(){若干命令行} • 调用函数的格式为: functionname param1 param2 …… • shell函数可以完成某些例行的工作;可以有自己的退出状态(用return可带返回值地返回脚本中函数调用下一条语句);可以作为if、while等控制结构的条件。 • 在函数定义时不用带参数说明,但在调用函数时可以带有参数,此时shell将把这些参数分别赋予相应的位置参数$1、$2、...及$*
shell函数(续) 例:函数返回值测试 #!/bin/sh #func check() { if [ $1 = $2 ] then return 0 else return 1 fi } echo “Input two numbers” read a b if check $a $b then echo "equal" else echo "unequal" fi 执行结果: $ sh func Input two numbers 2 3 unequal $ sh func Input two numbers 2 2 equal
That’s all Thank you!