shell脚本流程控制
1.if语句
单分支: if 判断条件; then 双分支: if 判断条件; then 条件为真的分支代码 else 条件为假的分支代码 fi 多分支: if 判断条件;then 条件为真的分支代码 elif 判断条件;then 条件为真的分支代码 elif 判断条件;then 条件为真的分支代码 else 不符合以上条件的代码段 fi 例:写一个脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个 参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数 #!/bin/bash if [ $# -lt 1 ];then echo "至少输入一个参数!" exit else if [ -f $1 ];then echo "$1的空白行数为:`sed -n '/^$/p' $1 | wc -l`" else echo "你输入的第一个参数不是文件!" exit fi fi
2、case语句
当条件的选择有多种时,if语句虽然能完成条件判断,但是代码不简洁,这时就可以选用case语句
语法: case 变量 in PAT1) 分支1 ;; PAT2) 分支2 ;; PAT3) 分支3 ;; *) 默认分支 ;; esac case支持glob风格的通配符: *: 任意长度任意字符 ?: 任意单个字符 []:指定范围内的任意单个字符 a|b: a或b 例:写一个脚本/root/bin/yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息 #!/bin/bash echo -e "Input yes or no!" read -s input input=`echo "$input" | tr 'A-Z' 'a-z'` case $input in "yes"|"y") echo "The input is yes" ;; "no"|"n") echo "The input is no" ;; *) echo "$input" ;; esac
3、for循环
for 变量名 in 列表; do 循环体 done 执行机制: 依次将列表中的元素赋值给“变量名” ; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束 例:用for循环打印99乘法表 #!/bin/bash line=1 for i in `seq 1 9`; do for k in `seq 1 $i`; do echo -ne "${k}*${i}"="$[$k*$i]\t" done echo done
4、while循环
while CONDITION; do 循环体 done CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“ true”,则执行一次循环; 直到条件测试状态为“ false”终止循环 因此: CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正 进入条件: CONDITION为true 退出条件: CONDITION为false 例:while实现打印99乘法表 #!/bin/bash i=1 while [ $i -le 9 ]; do j=1 while [ $j -le $i ]; do echo -ne "${j}x${i}=$[$j*$i]\t" ((j++)) done echo ((i++)) done
5、until循环
until循环和while循环相反,while循环当条件判断是为真时执行,为假跳出循环。until循环则当条件判断为假时执行,为真时跳出循环
until CONDITION; do 循环体 done 进入条件: CONDITION 为false 退出条件: CONDITION 为true
6、循环控制语句continue和break
continue为跳出这一次循环,continue#为提前结束第#层的本轮循环,而直接进入下一轮判断;最内层为第1层 break为跳出这一层循环体,break#为结束第n层循环体;最内层为一层
7、创建无限循环
主要运用while和until的特性,使用while true;或者until false使循环体一直运行 一般使用exit和循环控制语句break跳出循环
8、特殊用法
while循环的特殊用法(遍历文件的每一行): while read line; do 循环体 done < /PATH/FROM/SOMEFILE 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line 例:扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功。 #!/bin/bash while read line; do note=`echo "$line" | cut -d: -f5` usr_name=`echo $line | cut -d: -f1` [[ -z $note ]] && chfn -h 62985600 -f 62985600 $usr_name &> /dev/null && echo "$usr_name GECOS 信息修改成功!" done < /etc/passwd for循环的特殊格式: for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)) do 循环体 done 控制变量初始化:仅在运行到循环代码段时执行一次 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断 类似C语言语法: 双小括号方法,即((…))格式,也可以用于算术运算 #I=10 #((I++))
9、select循环
select循环用来实现shell程序中的交互,能显示菜单模式的输出,显示PS3提示符,等待用户输入,
用户输入菜单中的摸个数字,执行相应命令
用户输入被保存在REPLY变量中
select variable in list do 循环体命令 done select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c退出循环。 select 经常和 case 联合使用与 for 循环类似,可以省略 in list , 此时使用位置参量 例:输出UID大于等于1000的用户,等待用户输入菜单选项,输出对应的用户的passwd字段 #!/bin/bash echo "UID大于等于1000的用户列表:" select i in `cat /etc/passwd | cut -d: -f1,3 |sort -n -t: -k2 |awk -F: '{if($2>=1000) print $0;}'`; do name=`echo "$i" | cut -d: -f1` grep "^$name:" /etc/passwd done
shell脚本函数
介绍:
函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。
函数和shell程序比较相似,区别在于:Shell程序在子Shell中运行而Shell函数在当前Shell中运行。
因此在当前Shell中,函数可以对shell中变量进行修改
函数由两部分组成:函数名和函数体。 语法一: function f_name { ... 函数体 ... } 语法二: f_name() { ... 函数体 ... } 函数的使用: 可在交互式环境下定义函数 可将函数放在脚本文件中作为它的一部分 可放在只包含函数的单独文件中 函数必须先定义,再调用 调用:函数只有被调用才会执行; 调用:给定函数名出现的地方,会被自动替换为函数代码 函数的生命周期:被调用时创建,返回时终止 函数有两种返回值: 函数的执行结果返回值: (1) 使用echo或printf命令进行输出: (2) 函数体中调用命令的输出结果 函数的退出状态码: (1) 默认取决于函数中执行的最后一条命令的退出状态码 (2) 自定义退出状态码, 其格式为:return 从函数中返回,用最后状态命令决定返回值 return 0 无错误返回。 return 1-255 有错误返回 函数可以接受参数: 传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“ testfunc arg1 arg2 ...” 在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量 变量作用域: 环境变量:当前shell和子shell有效 本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数。 局部变量:函数的生命周期;函数结束时变量被自动销毁 注意:如果函数中有局部变量,如果其名称同本地变量, 使用局部变量。 在函数中定义局部变量的方法 local NAME=VALUE 函数递归: 函数直接或间接调用自身 注意递归层数 例: 示例:求5的阶层 fact.sh #!/bin/bash # fact() { if [ $1 -eq 0 -o $1 -eq 1 ]; then echo 1 else echo $[$1*$(fact $[$1-1])] fi } fact 5
作业、练习
1、写一个脚本,用循环显示三角形
[root@ _161_ ~/bin/8-17_study]# cat dao_san_jiao.sh #!/bin/bash read -t 30 -p "Input num:" num for i in `seq 1 $num`; do line="" black=$[(2*$i)-1] space=$[$num-$i] for j in `seq 1 $space`; do line=$line" " done for k in `seq 1 $black` do line=$line"*" done echo "$line" done [root@ _162_ ~/bin/8-17_study]# bash dao_san_jiao.sh Input num:5 * *** ***** ******* *********
2、用until循环实现国际象棋棋盘
[root@ _165_ ~/bin/8-17_study]# cat chess_until.sh #!/bin/bash black="\033[47m \033[0m" white="\033[40m \033[0m" i=1 until [ $i -gt 8 ]; do j=1 until [ $j -gt 8 ]; do [ $[($i+$j)%2] -eq 0 ] && echo -ne "$white" [ $[($i+$j)%2] -ne 0 ] && echo -ne "$black" ((j++)) done echo ((i++)) done
3、写一个脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)
[root@ _177_ ~/bin]# cat 8-15_study/filetype.sh #!/bin/bash read -t 30 -p "Input file!:" filename echo $filename [ -z $filename ] && echo "你没有输入文件名!" && exit ! [ -a $filename ] && echo "你输入的文件不存在!" && exit if [ -f $filename ];then [ -h $filename ] && echo "$filename is link file!" || echo "$filename is file!" elif [ -d $filename ];then echo "$filename is directory!" else echo "${filename} is other file!" fi [root@ _178_ ~/bin]# bash 8-15_study/filetype.sh Input file!:e e 你输入的文件不存在! [root@ _179_ ~/bin]# bash 8-15_study/filetype.sh Input file!:/etc/issue /etc/issue /etc/issue is file!
4、写一个脚本/root/bin/checkint.sh,判断用户输入的参数是否为正整数
[root@ _181_ ~/bin]# cat 8-15_study/chkint.sh #!/bin/bash read -t 30 -p "输入一个数:" num [[ $num == "0" ]] && echo "你输入的数为0!" && exit expr $num + 0 &>/dev/null if [ $? -eq 0 ];then if [ $num -gt 0 ];then echo "你输入的数为正整数!" else echo "你输入的数为负整数!" fi else echo "你输入的不是整数!" fi [root@ _182_ ~/bin]# bash 8-15_study/chkint.sh 输入一个数:e 你输入的不是整数! [root@ _183_ ~/bin]# bash 8-15_study/chkint.sh 输入一个数:4.5 你输入的不是整数! [root@ _184_ ~/bin]# bash 8-15_study/chkint.sh 输入一个数:3 你输入的数为正整数! [root@ _185_ ~/bin]# bash 8-15_study/chkint.sh 输入一个数:-2 你输入的数为负整数!
5、写一个脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显
示其存在,否则添加之;显示添加的用户的id号等信息
[root@ _186_ ~/bin]# cat 8-15_study/creatuser.sh #!/bin/bash read -t 30 -p "Input username:" username id $username &>/dev/null if [ $? -eq 0 ];then echo "用户已存在" else useradd $username [ $? -eq 0 ] && id $username && echo -e "成功创建了\e[32;5m${username}\e[0m用户" || echo "输入了非法用户名!" fi [root@ _187_ ~/bin]# bash 8-15_study/creatuser.sh Input username:cej 用户已存在 [root@ _188_ ~/bin]# bash 8-15_study/creatuser.sh Input username:cej2 uid=1008(cej2) gid=1008(cej2) 组=1008(cej2) 成功创建了cej2用户
6、判断/var/目录下所有文件的类型
[root@ _191_ ~/bin]# cat for_script/var_type_pwd.sh #!/bin/bash cd /var for i in `ls -A /var`; do echo "$i is `file -b $i`" done [root@ _192_ ~/bin]# bash for_script/var_type_pwd.sh account is directory adm is directory cache is directory crash is directory db is directory empty is directory games is directory gopher is directory kerberos is directory lib is directory local is directory lock is symbolic link to `../run/lock' log is directory mail is symbolic link to `spool/mail' nis is directory opt is directory preserve is directory run is symbolic link to `../run' spool is directory tmp is sticky directory .updated is ASCII text www is directory yp is directory
7、添加10个用户user1-user10,密码同用户名
[root@ _196_ ~/bin/for_script]# cat user_add_1_10.sh #!/bin/bash for i in `seq 1 10`; do id user$i &>/dev/null if [ $? -eq 0 ];then echo "user$i exist!" else useradd user$i echo "user$i" | passwd --stdin user$i &>/dev/null [ $? -eq 0 ] && echo "user$i create successful!" || echo "user$i create faild !" fi done [root@ _197_ ~/bin/for_script]# bash user_add_1_10.sh user1 create successful! user2 create successful! user3 create successful! user4 create successful! user5 create successful! user6 create successful! user7 create successful! user8 create successful! user9 create successful! user10 create successful!
8、、 /etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,以K开头的文件输出为文件加stop
,以S开头的文件输出为文件名加start;“ K34filename stop” “S66filename start”
[root@ _200_ ~/bin/for_script]# cat K_S_Find.sh #!/bin/bash K_num=0 S_num=0 cd /etc/rc.d/rc3.d for i in `ls -A /etc/rc.d/rc3.d`; do if echo "$i" | grep -q "^K";then ((K_num++)) echo "$i stop" elif echo "$i" | grep -q "^S";then ((S_num++)) echo "$i start" else echo "$i" fi done echo "K:$K_num" echo "S:$S_num" [root@ _201_ ~/bin/for_script]# bash K_S_Find.sh K50netconsole stop S10network start K:1 S:1
9、写一个脚本,提示输入正整数n的值,计算1+2+3+…n的总和
[root@ _206_ ~/bin/for_script]# cat int_sum.sh #!/bin/bash read -t 30 -p "Input int:" int_num expr $int_num + 0 &>/dev/null ! [ $? -eq 0 ] && { echo "你输入了非数字或者零!";exit; } #判断是否是整数 ! [ $int_num -gt 0 ] && { echo "你输入的不是正数!" ;exit; } #判断是否是正数 sum=0 for i in `seq 1 $int_num`; do let sum=${sum}+$i done echo "sum is $sum" [root@ _207_ ~/bin/for_script]# bash int_sum.sh Input int:100 sum is 5050
10、写一个脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态
[root@ _209_ ~/bin/for_script]# cat ping_for.sh #!/bin/bash for i in `seq 76 99`; do ping -c 1 -w1 10.1.252.$i &>/dev/null if [ $? -eq 0 ];then echo -e "\033[33m10.1.0.$i is online!\033[0m" else echo "10.1.0.$i is offline!" fi done [root@ _210_ ~/bin/for_script]# bash ping_for.sh 10.1.0.76 is offline! 10.1.0.77 is online! 10.1.0.78 is offline! 10.1.0.79 is offline! 10.1.0.80 is offline! 10.1.0.81 is offline ...
待续!
原创文章,作者:M20-1--孔祥文,如若转载,请注明出处:http://www.178linux.com/38002
评论列表(1条)
文章对选择语句和循环语句的语法总结的很详细,同时也通过相应的示例加深了自己对脚本的理解,脚本的学习没有什么捷径。靠平常的积累,平时写的多了,看的多了,我们才能运用自如,我们可以在平时的写作中尝试用不同的语法总结出他们的不同点和最适用的场景哦。