shell脚本应用(三)
目录
使用for循环语句
当面对各种列表重复任务是,使用简单的if语句已经难以满足要求,而顺序编写全部代码更是显得异常繁琐、困难重复,for循环语句可以很好地解决类似问题。
for语句的结构
使用for循环语句时,需要指定一个变量及可能的取值列表,针对每个不同的取值重复执行相同的命令序列,直到变量使用完退出循环。在这里“取值列表”称为for语句的执行条件,其中包括多个属性相同的对象,需要预先指定(如通讯录,IP黑名单)。
for循环语句的语法结构如下。
fro 变量名 in 取值列表
do
命令序列
done
上述语句结构中,for语句的操作对象为用户指定名称的变量,并通过in关键字为变量预先设置了一个取值列表, 多个取值之间以空格进行分隔。位于do...done之间的命令序列称为循环体,其中的执行语句需要引用变量以完成相应的任务。
for语句的执行流程:
首先将列表中的第一个取值赋给变量,并执行do...done循环体中的命令序列;然后将列表中的第二个取值赋给变量,并执行循环体中的命令序列......以此类推,直到列表中的所有取值用完,最后将跳至done语句,表示结束循环,如图所示。
for语句应用示例
1)根据姓名列表批量添加用户
根据人事部门给出的员工姓名的拼音列表,在linux服务器中添加相应的用户账户,初始密码均设置为“123456”。其中,员工姓名列表中的账号数量并不固定,而且除了要求账号名称是拼音之外,并无其他特殊规律。
针对上述要求,可先指定员工列表users.txt,然后编写一个名为uaddfor.sh的shell脚本,从users.txt文件中读取各用户名称,重复执行添加用户,设置初始密码的相关操作。
[root@localhost ~]# vim /root/users.txt //用做测试的列表文件
zhangsan
wangwu
zhaoliu
[root@localhost ~]# vim uaddfor.sh //批量添加用户的脚本
[root@localhost ~]# chmod +x uaddfor.sh
#!/bin/bash
A=$(cat /root/users.txt)
for B in $A
do
useradd $B
echo "123456" | passwd --stdin $B &> /dev/null
done
[root@localhost ~]# ./uaddfor.sh //测试并确认执行结果
[root@localhost ~]# tail -3 /etc/passwd
zhangsan:x:1001:1001::/home/zhangsan:/bin/bash
wangwu:x:1002:1002::/home/wangwu:/bin/bash
zhaoliu:x:1003:1003::/home/zhaoliu:/bin/bash
若要删除addfor.sh脚本所添加的用户,只需参照上述脚本代码,将for循环体中添加用户的命令序列改为删除用户的操作即可。例如,建立一名为udelfor.sh的脚本如下所示。
[root@localhost ~]# vim udelfor.sh //批量删除用户的脚本
#!/bin/bash
A=$(cat /root/users.txt)
for B in $A
do
userdel -r $B &>/dev/null
done
[root@localhost ~]# chmod +x udelfor.sh
[root@localhost ~]# ./udelfor.sh //测试并确认执行结果
[root@localhost ~]# id zhangsan
id: zhangsan: no such user //提示无此用户
2)根据IP地址列表检查主机状态
根据包含公司各服务器IP地址的列表文件,检查其中各主机的ping连通性,输出个主机是否启动,关闭。其中,服务器的数量并不固定,个服务器的IP地址之间无特殊规律。
针对此案例要求,可先指定IP地址列表文件ipadds.txt,然后编写一个名为chkhosts.sh的shell脚本,从ipadds.txt文件中读取各服务器的IP地址,执行ping连通性测试,并根据测试结果输出相应的提示信息。
[root@localhost ~]# vim /root/ipadds.txt
192.168.1.10
192.168.1.20
192.168.1.30
192.168.1.40
192.168.1.50
@localhost ~]# vim chkhosts.sh
#!/bin/bash
A=$(cat /root/ipadds.txt)
for IP in $A
do
ping -c 3 -i 0.2 -W 3 $IP &>/dev/null
if [ $? -eq 0 ]
then
echo "Host $IP is up"
else
echo "Host $IP is down"
fi
done
[root@localhost ~]# chmod +x chkhosts.sh
[root@localhost ~]# ./chkhosts.sh
Host 192.168.1.10 is down
Host 192.168.1.20 is down
...
上述执行脚本中,没有ipadds.txt文件中的IP地址,设置其他IP只需要在ipadds.txt文件中添加IP地址信息即可。例如,设置本机IP为1.10后在执行脚本查看结果,如下所示。
[root@localhost ~]# ifconfig ens33 192.168.1.10
[root@localhost ~]# ./chkhosts.sh
Host 192.168.1.10 is up
Host 192.168.1.20 is down
...
上述脚本代码中,do...done循环体内嵌套使用了if条件选择语句,用来针对不同IP地址的测试结果进行判断,并输出相应的提示信息。嵌套可以理解为镶嵌、套用,就是在已有的语句,函数中再多加一个或多个语句、函数等。实际上,if语句、for语句及其他各种shell脚本语句都是可以嵌套使用的。
使用while循环语句
for循环语句非常适用于列表对象无规律,且列表来源固定(如某个列表文件)的场合。而对与要求控制循环次数,操作对象按数字顺序编号,按特定条件执行重复操作等情况,则更适合使用另外一种循环——while语句。
while语句的结构
使用while循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不在满足时为止。在脚本应用中,应该避免出现死循环的情况,否则后边的命令操作将无法执行。因此,循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环。
while循环语句的语法结构如下所示。
while 条件测试操作
do
命令序列
done
while语句的执行流程:
首先判断while后的条件测试操作结果,如果条件成立,则执行do...done循环体中的命令序列;返回while后再此判断条件测试结果,如果条件 仍然成立,则继续执行循环体;再次返回while后,判断条件测试结果......如此循环,直到while后的条件测试结果不再成立为止,最后转跳到done语句,表示结束循环。
使用while循环语句时,有两个特殊的条件测试操作,即true(真)和false(假)。使用true作为条件时,表示条件永远成立,循环体内的命令序列将无限执行下去,除非强制终止脚本(或通过exit语句退出脚本);反之,若false作为条件,则循环体将不会被执行。这两个特殊条件也可以用在if语句的条件测试中。
while语句应用示例
1. 批量添加规律编号的用户
在一些技术培训和学习领域,出于实验或测试的目的,需要批量添加用户账号,这些用户的名称中包含固定的前缀字串,并按照数字顺序依次进行编号,账号的数量往往是固定的。例如,若要添加20个用户,名称依次为stu1,stu2,...,stu20,可以参考以下操作。
[root@localhost ~]# vim uaddwhile.sh
#!/bin/bash
A="stu"
i=1
while [ $i -le 20 ]
do
useradd ${A}$i
echo "123456" | passwd --stdin ${A}$i &> /dev/null
let i++
done
[root@localhost ~]# chmod +x uaddwhile.sh
上述脚本代码中,使用变量”i“来控制用户名称的编号,初始赋值为1,并且当取值大于20时终止循环。在循环体内部,通过语句“let i++” ,等同于i=$(expr $i + 1)来使用变量i的值增加1,因此当执行第一次循环后i的值将变为2,执行第二次循环后i的值将变为3,......,以此类推。
测试并确认uaddwhile.sh脚本的执行结果如下。
[root@localhost ~]# ./uaddwhile.sh
[root@localhost ~]# grep "stu" /etc/passwd | tail -3
stu18:x:1018:1018::/home/stu18:/bin/bash
stu19:x:1019:1019::/home/stu19:/bin/bash
stu20:x:1020:1020::/home/stu20:/bin/bash
若要删除uaddwhile.sh脚本所添加的用户,只需要参考上述脚本代码,将while循环体中添加用户的命令序列改为删除用户的操作即可。
[root@localhost ~]# vim udelwhile.sh //批量删除用户的脚本
#!/bin/bash
A="stu"
i=1
while [ $i -le 20 ]
do
userdel -r ${A}$i
let i++
done
[root@localhost ~]# ./udelwhile.sh //测试并确认执行结果
[root@localhost ~]# id stu20
id: stu20: no such user //用户stu20不存在
2. 猜价格游戏
案例要求如下:由脚本预先生成一个随机的价格数目(0-999)作为实际价格,判断用户猜测的价格是否高出或低于实际价格,给出相应提示后再此要求用户猜测;一直到用户猜中实际价格位置,输出用户共猜测的次数,实际价格。
针对上述要求,主要设计思路如下:通过环境变量RANDOM可获得一个小于2的16次方的随机整数,计算其与1000的余数即可获得0~999的随机价格,反复猜测操作可以用个以true作为测试条件的while循环实现,当用户猜中实际价格时终止循环,判断猜测价格与实际价格的过程采用if语句实现,嵌套在while循环体内;使用变量来记录猜测次数。
[root@localhost ~]# vim pricegame.sh
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格范围为0-999,猜猜看是多少?"
while true
do
read -p "请输入你猜测的价格数目:" INT
let TIMES++
if [ $INT -eq $PRICE ] ; then
echo "恭喜你猜对了,实际价格时$PRICE"
echo "你总共猜测了 $TIMES 次"
exit 0
elif [ $INT -gt $PRICE ] ; then
echo "太高了!"
else
echo "太低了!"
fi
done
[root@localhost ~]# chmod +x pricegame.sh
测试并确认pricegame.sh脚本的执行结果如下
[root@localhost ~]# ./pricegame.sh
商品实际价格范围为0-999,猜猜看是多少?
请输入你猜测的价格数目:500
太高了!
请输入你猜测的价格数目:400
太高了!
请输入你猜测的价格数目:300
太低了!
请输入你猜测的价格数目:350
太高了!
请输入你猜测的价格数目:340
太高了!
请输入你猜测的价格数目:320
恭喜你猜对了,实际价格时320
你总共猜测了 6 次
学会条件测试操作及if,for,while语句的使用以后,已基本可以编写一般的管理脚本。当然只有大家对各种命令,管道,重定向等命令操作融汇贯通,才能编写出更优秀的脚本程序。shell脚本的应用灵活多变,即使是完成同一项任务,也可能有许多种不同的实现方式,大家应该勤加练习,在实践过程中慢慢去领会。
使用case分支语句
case语句可以使脚本程序的结构更加清晰、层次分明。
case语句的结构
case语句主要适用于以下情况;某个变量存在多种取值,需要对其中的每一种取值分别执行不同的命令序列。这种情况与多分支的if语句非常相似,只不过if语句需要判断多个不同的条件,而case语句只是判断一个变量的不同取值。
case分支语句的语法结构如下所示
case 变量值 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
......
*)
默认命令序列
esac
在上述语句结构中,关键字case后面跟的是“变量值”,即“$变量名”,这点需要与for循环语句的结构加以区别。整个分支结构包括在case...esac之间,中间的模式1,模式2, ...,*对应为变量的不同取值(程序期望的取值),其中 “ * ”号作为通配符,可以匹配任意值。
case语句的执行流程:
首先使用“变量值”与模式1进行比较,若取值相同则执行模式1后的命令序列,直到遇见双分号“;;”后转跳至esac,表示结束分支;若与模式1不相匹配,则继续与模式2进行比较,若取值相同则执行模式2后的命令序列,只到遇见双分号“;;”后跳转至esac,表示结束分支...以此类推,若找不到任何匹配的值,则执行默认模式“*)”后的命令序列,只到遇见esac后结束分支。
使用case分支语句时,有几个值得注意的特点如下所述。
-
case行尾必须为单词“in”,每一模式必须以左括号“)”结束
-
双分号“;;“表示命令序列的结束。
-
模式字符串中,可以用方括号表示一个连续的范围,如“[0-9]”; 还可以用竖行符号“|”表示或,如“A|B"。
-
最后的“*)”表示默认模式,其中的” * “相当于通配符。
case语句应用示例
1)检查用户输入的字符类型
提示用户号从键,盘输入的一个字符,通过case语句判断字符是否为字母,数字或者其他控制字符,并给出相应的提示信息。
[root@localhost ~]# vim hitkey.sh
#!/bin/bash
read -p "请输入一个字符,并按Enter键确认:" KEY
case "$KEY" in
[a-z]|[A-Z]) //匹配任意字母
echo "您输入的是 字母."
;;
[0-9]) //匹配任意数字
echo "您输入的是 数字."
;;
*) //默认模式,匹配任意字符
echo "您输入的是 空格、功能键或其他控制字符."
esac
[root@localhost ~]# chmod +x hitkey.sh
测试并确认hitkey.sh脚本执行结果如下
[root@localhost ~]# ./hitkey.sh
请输入一个字符,并按Enter键确认:f
您输入的是 字母.
[root@localhost ~]# ./hitkey.sh
请输入一个字符,并按Enter键确认:1
您输入的是 数字.
[root@localhost ~]# ./hitkey.sh
请输入一个字符,并按Enter键确认:^[[19~
您输入的是 空格、功能键或其他控制字符.
2)编写系统服务脚本
编写一个名为myprog的系统服务脚本,通过位置变量$1指定的start,stop,restart,status控制参数,分别用来启动,停止,重启sleep进程,以及查看sleep进程的状态。其中,命令sleep用来暂停指定秒数的时间,这里仅用做测试,在实际运维工作中应将sleep改为相应后台服务的控制命令序列。
[root@localhost ~]# vim myprog
#!/bin/bash
case "$1" in
start)
echo -n "正在启动sleep服务 ..."
if sleep 7200 &
then //在后台启动sleep进程
echo "OK"
fi
;;
stop)
echo -n "正在停止sleep服务 ..."
pkill "sleep" &> /dev/null
echo "OK" //停止sleep进程
;;
status)
if pgrep "sleep" &>/dev/null ; then //判断并提示sleep进程状态
echo "sleep服务已经启动"
else
echo "sleep服务已经停止"
fi
;;
restart) //先停止、在启动服务
$0 stop
$0 start
;;
*) //默认显示用法信息
echo "用法:*0 {start|stop|status|restart}"
esac
[root@localhost ~]# chmod +x myprog
[root@localhost ~]# ./myprog start
正在启动sleep服务 ...OK
[root@localhost ~]# ./myprog status
sleep服务已经启动
[root@localhost ~]# ./myprog stop
正在停止sleep服务 ...OK
[root@localhost ~]# ./myprog reload
用法:*0 {start|stop|status|restart}
在Linux系统中,源码软件包编译安装后提供的服务控制脚本使用了case分支语句;也有一些源码包没有提供服务控制脚本,编译安装后可参照上例自行编写服务控制脚本。平时控制各种系统服务时,提供的start,stop,restart等位置参数,正是由case语句结构来识别并完成相应的操作的。若要将myporg服务交给systemd来管理,还需要在/lib/systemd/system 目录下添加相应的myprog.service配置文件。
相关文章
- 图遍历算法的应用
- Shell脚本的应用场景及工作原理
- Shell case条件语句的应用实践
- shell–2–shell变量 定义变量 使用变量 只读变量 删除变量 变量类型 Shell字符串 shell函数详解程序员
- Linux下执行Shell脚本的技巧(linux执行shell脚本)
- 走进Linux世界:命令行与Shell脚本编程指南(linux命令行与shell脚本编程大全)
- 备份自动化运维:Shell脚本实现MySQL数据库备份(shell脚本mysql)
- 数据库操作Shell脚本与Oracle数据库实现自动操作(shell与oracle)
- 开启Linux系统Shell,探索更多精彩(linux系统shell)
- 脚本Linux下如何创建Shell脚本(linux创建shell)
- 脚本使用Linux启动Shell脚本的步骤(linux启动shell)
- Linux Shell编程:为初学者开启新世界(linux shell编程入门)
- 命令深入了解Linux,学会常用Shell命令(linux常用shell)
- Linux平台上的Java应用部署全指南(linuxjava部署)
- Linux定时自动运行Shell脚本,极大提升工作效率(linux定时执行shell脚本)
- 如何在MySQL中使用Shell操作数据(mysql中shell)
- Linux下使用Redis优化你的Shell命令(shell上redis)
- 使用Shell脚本彻底清理Redis缓存(shell清理redis)
- Oracle Shell实现智能脚本管理(oracle shell)