2017 08-24 SHELL脚本编程进阶

  • 流程控制

  • 过程式编程语言:
    顺序执行
    选择执行
    循环执行

一.条件选择if语句

类型:选择执行 
注意:if语句可嵌套 
单分支

if 判断条件;then 
    条件为真的分支代码 
fi 
 

双分支

if 判断条件; then
 条件为真的分支代码 
else 
条件为假的分支代码 
fi

多分支

if 判断条件1; then 
条件为真的分支代码 
elif 判断条件2; then 
条件为真的分支代码
elif 判断条件3; then 
条件为真的分支代码 
else 
以上条件都为假的分支代码
 fi  
逐条件进行判断,第一次遇为“真”条件时,执行其分支, 而后结束整个if语句

注意 type if ——
  • 实验小练习

例题1:判断年龄大小,如果超过20岁,则显示"you are too old"如果小于20岁,则显示"you are so yong"


image.png

嵌套方式:


image.png

注意:判断数字最好使用[[ "$age" =~ ^[0-9]+$ ]]
例题2:判断文件是否以.sh后缀
image.png

image.png

else 条件分支例题

例题:判断成绩


image.png

二.条件判断:case语句

case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
... *)
默认分支
;;
esac
case支持glob风格的通配符:
*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b

练习1:选择范围内的数字


image.png

练习2:编辑菜单并选择


image.png

image.png

练习3:判断yes or no
image.png
image.png

三.循环

  • 循环执行
    将某代码段重复运行多次
    重复运行多少次:
    循环次数事先已知 循环次数事先未知
    有进入条件和退出条件 
  • for, while, until

(一)for循环

  • 格式:
    for "变量名——直接写变量名 "in 列表;do
    循环体
    done 
    执行机制: 依次将列表中的元素赋值给“变量名”; 每次赋值后即执 行一次循环体; 直到列表中的元素耗尽,循环结束
  • 列表生成方式:
    (1) 直接给出列表
    (2) 整数列表: (a) {start..end} (b) $(seq [start [step]] end)
    (3) 返回列表的命令 $(COMMAND)
    (4) 使用glob,如:.sh
    (5) 变量引用; $@, $

例题1:创建十个用户,并设置密码

vim create.sh

 #!/bin/bash
  2 > /root/user.log
  3 for id in  {1..10} ; do
  4    useradd user$id && echo user$id is created
  5    password=`tr -dc 'a-zA-Z0-9'< /dev/urandom |head -c 6`
  6    echo user$id:$password >> /root/user.log
  7    echo $password |passwd --stdin user$id &> /dev/null
  8    passwd -e user$id&> /dev/null——登录后设置新的密码
  9 done
删除账号 : for id in {1..10};do userdel  -r user$id ;done
        或者:echo user{1..10}|xargs -n1 userdel -r 

例题2:和172.18.254这个网段的ip进行连接

1 #!/bin/bash
  2 netid=172.18.254
  3 > /root/ip.log
  4 for id in {1..254};do
  5   {
  6   if ping -c1 -w1 $netid.$id &> /dev/null;then
  7       echo $netid.$id |tee -a /root/ip.log
  8   fi
  9   } &——后台执行,类似并行执行,节省时间
 10 done
 11 wait——等待时间help  wait 
wait: wait [id]
    Wait for job completion and return exit status.

(二)while 循环

(1)while 的使用格式
while 判断条件 ;do
当判断的条件为真时,执行while 循环
当判断条件为假时,不执行while 循环
执行原理:当使用while 循环时,首先要判断条件的真假,符合条件时,进入循环体执行一次,然后再次判断,直到判断条件为假时,退出循环不在执行

例子1:编写脚本,求100以内所有正奇数之和

#!/bin/bash
i=1
sum=0
while [ $i -lt 100 ];do
   let sum+=i
   let i=i+2
done
 echo "the sum is $sum"
用for 来计算;
#!/bin/bash
sum=0
for i in {1..100..2};do
let sum+=i
done
echo "the sum is $sum"

例题2;编写脚本,提示请输入网络地址,如192.168.0.0,判断 输入的网段中主机在线状态,并统计在线和离线主机各多少

#!/bin/bash
up=0
down=0
hostid=1
read -p "please input the netid:" network
netid=`echo $network| cut -d "."  -f1-3`
while [ $hostid -le  10];do
if ping  -c1 -w1 $network &> /dev/null;then
echo "the $netid.$hostid is up"
    let up++
else
echo  "the $netid.$hostid is down"
   let down++
fi
  let hostid++
done
echo "the up is $up"
echo "the down is $down"

例题三:编写脚本,打印九九乘法表

#!/bin/bash
i=1
while [ $i -le 10 ];do
 j=1
  while [ $j -le 10 ];do
  echo -ne "$j*$i=$[j*i]\t"
  let j++
done
let i++
echo
done 

例题4;编写脚本,利用变量RANDOM生成10个随机数字,输出 这个10数字,并显示其中的最大值和最小值

max=$ran
min=$ran
i=0
while [ $i -le 10 ];do
  ran=$RANDOM
echo $ran
if [ $i -eq 0 ];then
  max=$ran
min=$ran
fi
if [ $ran -gt $max ];then
    max=$ran
elif [ $ran -lt $min];then
min=$ran
fi
let i++
done
echo "the max is $max"
echo "the min is $min"

例题5:编写脚本,实现打印国际象棋棋盘

#!/bin/bash
i=0
while [ $i -lt 8 ];do
j=0
while [ $j  -lt 8 ];do
if [ $[ $[j+i]%2 ]  -eq 0 ];do
  echo -ne "\033[43m  \033[0m\t"
else 
echo -ne "\033[41m  \033[0m\t"
fi
let j++
done
let i++
echo
done
方法二:
#!/bin/bash
i=0
while [  $i -lt 4 ];do
j=0
while [   $j -lt 8 ];do
if   [  $j -lt 4  ];then
echo -ne  "\033[41m  \033[0m\t"
echo  -ne "\033[43m  \033[0m\t"
if   [ $j  -eq 3  ];then
echo
fi
else 
 echo -ne "\033[43m  \033[0m"
 echo  -ne "\033[41m  \033[0m"
fi
  if [  $j -eq 7 ];then
echo
fi
let j++
done
let i++
done

while 的特殊用法

  • while循环的特殊用法(遍历文件的每一行):
    while read line; do 循环体 done < /PATH/FROM/SOMEFILE 
    依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将 行赋值给变量line

例:查看/etc/passwd中用户的id,如果小于500则为系统用户,大于500位普通用户

while read lines ;do
userid =`echo $lines| cut -d ":" -f3`
username=`echo $lines|cut -d ":" -f1`
if [ $userid-lt 500   ];then
echo "the $username is sysuser"
else echo "the $username is commonuser"
fi
done < /etc/passwd
image.png
  • 小练习

扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填 充用户名和单位电话为62985600,并提示该用户的GECOS信 息修改成功。
while read lines ;do
GECOS=echo $lines|cut -d ":" -f5
usrename=echo $lines |cut -d ":" -f1
if [ -z $GECOS ];then
chfn -f "$username" -p "62985600" &> /dev/null
echo "the change is successful"
else
echo "the user is not empty"
fi
done < /etc/passwd

  • while true; do 循环体 done

示例:检查httpd 的状态,如果处于开启状态,就不执行,如果处于关闭状态,就开启服务,每五秒执行一次,实现实时监控

while true ;do
if killall -0 httpd &> /dev/null ;then
   .....
else 
systemctl restart httpd &>/dev/null
echo  ` date "+%F %T" `  systemctl restart >> /app/httpd.log
fi
sleep5
done  
  • until false; do 循环体 done

(三)until循环

  • 格式: until 判断条件 ;do
    循环体
    done
  • 判断条件为假的时候进入循环体,执行命令,与while条件相反
    判断条件为为真的时候,退出循环

(四)循环控制语句continue

用于循环体中 
continue [N]:
提前结束第N层的本轮循环,而直接进入下一 轮判断;最内层为第1层
while CONDTIITON1; do
CMD1 ...
if CONDITION2; then
continue
fi
CMDn ...
done

例1:

i=0
while [ $I -le 9 ];do
if [ $i -qe 5 ];then
continue
fi
echo i=$i
let i++
done

image.png

如果只是不显示5,而后续的数字继续打印,则
i=0
while [ $i -le 10 ];do
let i++
if [ $i -eq 5 ];then
continue
else
echo i=$i
fi
done
image.png

例2
for i in {1..10};do
for j in {1..10};do
echo -n "$j "
if [ %j -eq 5 ];then
continue 2
fi
done
echo
done
image.png

此时为continue 2,所以结束了第二层的本轮循环,也就是最外层循环

(五)循环控制语句break

用于循环体中 
break [N]:提前结束第N层循环,最内层为第1层 ——简单来说就是退出第N层整体的循环
while CONDTIITON1; do
CMD1 ...
if CONDITION2; then
break
fi
CMDn ...
done
例题;打印行和列
for i in {1..10};do
for j in {1..10};do
echo -n "$j "
[ $j -eq 5 ]&&break
done
echo
done


image.png

当输入break 2 时,整个外层循环都结束只打印 "1 2 3 4 5"

(六)循环控制shift命令

  • shift [n] 
    用于将参量列表 list 左移指定次数,缺省为左移一次。 
    参量列表 list 一旦被移动,最左端的那个参数就从列表中删 除。
    while 循环遍历位置参量列表时,常用到 shift 
    示例:
    whlie [ $# -gt 0 ];do
    echo "$*"
    shilt
    done


    image.png

    因此该命令可以用来创建用户
    while [ $# -gt 0 ];do
    id $i /dev/null && continue
    useradd $i && echo $i is created
    shift
    done

(七)特殊用法 for循环的特殊格式

  • 双小括号方法,即((…))格式,也可以用于算术运算 
    *双小括号方法也可以使bash Shell实现C语言风格的变量操作
    I=10
    ((I++)) 
    for循环的特殊格式:
    for ((控制变量初始化;条件判断表达式;控制变量的修正表达 式))
    do
    循环体
    done 
    控制变量初始化:仅在运行到循环代码段时执行一次 
    控制变量的修正表达式:每轮循环结束会先进行控制变量修 正运算,而后再做条件判断

例:用for的特殊循环格式实现1-100的加法运算

sum=0
for (( i=0;i<=100;i++  ));do
let sum+=i
done 
echo "the sum is $sum"
unset sum

(八)select循环与菜单

select variable in list
do
循环体命令
done 
select 循环主要用于创建菜单,按数字顺序排列的 菜单项将显示在标准错误上,并显示 PS3 提示符, 等待用户输入 
用户输入菜单列表中的某个数字,执行相应的命令 
用户输入被保存在内置变量 REPLY 中
select 是个无限循环,因此要记住用 break 命令退 出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环 
select 经常和 case 联合使用 
与 for 循环类似,可以省略 in list,此时使用位置 参量

例子:选择菜单

#!/bin/bash
PS3=" please input your menu: " 
select menu in lamian chaomian chaofan jiaozi baozi ;do
case $REPLY in
1)
    echo "the price is 10"
   ;;
2)
   echo  "the price is 15"
   ;;
3)
   echo " the price is 10 "
   ;;
4)
   echo "the price is 20"
   ;;
5)
   echo "the price is 10"
   ;;
*)
   echo "get out!"
  break       # select 本身是死循环,如果不执行break命令,则不会退出循环
  ;;
esac
done

(九)信号捕捉trap

  • trap '触发指令' 信号 自定义进程收到系统发出的指定信号后,将执行触发指令 ,而不会执行原操作 
  • trap '' 信号 忽略信号的操作 
  • trap '-' 信号 恢复原信号的操作 
    trap -p 列出自定义信号操作

例:

#!/bin/bash
trap 'echo "please press crtl+c" ' int   #此命令是int功能失效,只是打印"please press crtl+c"
trap -p
for ((i=1;i<=20;i++));do
echo $i
sleep1
done

trap ' '  int     # 忽略该操作
trap -p
for ((i=1;i<=20;i++));do
echo $i
sleep1
done

trap '_'  int     # 恢复int命令的操作
trap -p
for ((i=1;i<=20;i++));do
echo $i
sleep1
done
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容