###################################################
shell 脚本编程
一、循环结构
让特定代码重复执行
1.for循环
1)特点:循环的次数是固定的!
2)语法结构及特点
for 变量 in 值1 值2 …
do
命令
done
for ((i=1;i<10;i++)) /另一种写法
do
命令
done
###########################
seq 1 5 = seq 5 = echo {1…5} 默认起始位置为1
seq 1 2 5 --输出1 3 5 ,中间的2为步长
###########################
3)应用
输出3个chenguiz / 或 seq 3
或 {1…3}
for i in 1 2 3
do
echo “chenguiz”
done
###########################
快速创建1000个文件
for i in {1…1000}
do
touch /tmp/$i .txt
done
###########################
#读取用户文件,自动创建用户,初始密码为123456
for i in $(cat /root/user.txt)
do
id $i &>/dev/null
if [ $? -ne 0 ];then
useradd $i
echo “123456” | passwd --stdin KaTeX parse error: Expected 'EOF', got '&' at position 3: i &̲>/dev/null …i 用户创建成功!"
else
echo “KaTeX parse error: Expected 'EOF', got '#' at position 36: …er.log fi done #̲###############…i &>/dev/null
if [
?
−
e
q
0
]
;
t
h
e
n
e
c
h
o
"
172.40.55.
? -eq 0 ];then echo "172.40.55.
?−eq0];thenecho"172.40.55.i is up !” >>/root/up.log
else
echo “172.40.55.$i is down !” >>/root/down.log
fi
done
###########################
猴子摘了若干香蕉,吃了一半,多吃了一个。第二天吃了一半,又多吃了一个,以此类推,第九天,剩一个。
2.while循环
1)特点:不定次数,当判断为真时,一直循环执行;判断为假,则循环结束。
四循环的缺点:超耗内存,需sleep 0.1
2)结构
while [ 判断 ]
do
命令
done
while : /死循环固定格式 加冒号
do
命令
done
###########################
3)应用
#循环10次
i=1
while [
i
−
l
e
10
]
d
o
e
c
h
o
"
你
好
!
"
i
=
i -le 10 ] do echo "你好!" i=
i−le10]doecho"你好!"i=[i+1] 或let i++ /循环10次
done
###########################
#无限猜
num=$[RANDOM%100+1] /随机数取100的余数(0-99)加1 (1-100)
i=0 /先定义次数的变量
while :
do
read -p “有个随机数,你来猜猜看:” cai
let i++ /每猜一次加一
if [ $cai -eq
n
u
m
]
;
t
h
e
n
e
c
h
o
"
恭
喜
你
,
猜
对
了
!
共
猜
了
num ];then echo "恭喜你,猜对了!共猜了
num];thenecho"恭喜你,猜对了!共猜了i 次。"
exit /猜对并退出
elif [ $cai -gt KaTeX parse error: Expected 'EOF', got '#' at position 83: … fi done #̲###############…i*
j
=
j=
j=[i*j]”
#!/bin/bash
for i in seq 9
do
for j in seq $i
/
i
让
j
永
远
小
于
等
于
i
d
o
e
c
h
o
−
n
"
i让j永远小于等于i do echo -n "
i让j永远小于等于idoecho−n"i*
j
=
j=
j=[i*j] " /引号最后留个空格以隔开
done
echo /里面执行完后换行
done
###########################
二、服务脚本设计
1.case分支结构
1)case 语句 【简单的if:只能执行等于的值,判断等于和不等于】
case 变量 in
值1)
命令;; /命令结束用双分号
值2)
命令;;
值*)
命令;; /最后一个值的双分号可加可不加
esac
###########################
当运行/root/foo.sh redhat,输出为fedora ;当运行/root/foo.sh fedora,输出为redhat ;当没有任何参数或者参数不是 redhat 或者 fedora时,其错误输出产生以下信息: /root/foo.sh redhat|fedora
#!/bin/bash
case $1 in
readhat)
echo “nihao” /命令未完不用分号
echo “fedora”;; /命令结束用双分号
fedora)
echo “readhat”;;
*)
echo '/root/foo.sh redhat|fedora ';;
esac
###########################
创建选项
#!/bin/bash
case $1 in
-t)
touch $2;;
-c)
cat $2;;
-e)
vim $2;;
-d)
rm -rf $2;;
*)
echo “用法:test.sh [-t|-c|-e|-d]文件”
esac
###########################
read -p “请输入任意:” key
case $key in
[a-z]) /case的优势,支持[ ]
echo “字母”;;
[0-9])
echo “数字”;;
*)
echo “其他字符”;;
esac
三、函数及中断控制
1.shell函数
1)定义函数(脚本执行完就失效):
函数名() { 命令序列 } 或 function 函数名 { 命令序列 }
2)调用函数
# chen(){ mkdir -p $1; cd $1; pwd; } /定义
#chen /mnt/chen /调用
###########################
使用函数做计算
由用户在执行时提供2个整数值参数,计算这2个整数的加、减、乘、除结果
jsq(){
echo -n "$1+$2 = $[$1+$2] "
echo -n "$1-$2 = $[$1-$2] "
echo -n "$1*$2 = $[$1*$2] "
echo -n "$1/$2 = $[$1/$2] "
echo
}
echo “欢迎使用计算器”
jsq 12 55
jsq 55 90
###########################
定义函数 .
.(){ .|.& } /&放入后台,一直执行. 本身,死循环,耗光内存瞬间死机
###########################
定义颜色的函数,方便调用
cecho(){ echo -e “\033[$1m $2 \033[0m” }
cecho 32 ok
cecho 33 nihao
echo -en “\033[45m \033[0m” ;“\033[44m \033[0m”
2.中断及退出
- break:中断整个循环
continue:中断本次循环,进入下一次循环
exit:结束整个脚本 =kill
ssh 172.40.55. i “ p o w e r o f f ” / 直 接 把 i “poweroff” /直接把 i“poweroff”/直接把i关机
###########################
for i in {1…10}
do
[ $i -eq 5 ] && break /break显示到4之后就执行GameOver
echo $1 /continue跳过5显示所有
done /exit 显示到4就结束整个脚本
echo “Game Over !”
###########################
从键盘循环取整数(0结束)并求和,输出最终结果
sum=0
while :
do
read -p “请输入待累加的整数:” num / 键盘循环取整数
[ KaTeX parse error: Expected 'EOF', got '&' at position 17: …um -eq 0 ] &̲& break …[ sum + num ] /求和
done
echo “总和是:$sum ”
###########################
跳过1~20以内非6的倍数,输出其他数的平方值,设定退出代码为2
for i in {1…20} /1~20以内
do
[ $[i%6] -ne 0 ] && continue /非6的倍数
echo $[i*i] / 输出其他数的平方值
done
exit 2 / 设定退出代码为2
Top
NSD SHELL DAY03
1.案例1:使用for循环结构
2.案例2:使用while循环结构
3.案例3:基于case分支编写服务脚本
4.案例4:使用Shell函数
5.案例5:中断及退出
1 案例1:使用for循环结构
1.1 问题
本案例要求编写一个Shell脚本chkhosts.sh,利用for循环来检测多个主机的存活状态,相关要求及说明如下:
待检测的多个目标IP地址,存放在ipadds.txt文件内
ping检测可参考前一天的pinghost.sh脚本
脚本能遍历ping各主机,并反馈存活状态
执行检测脚本以后,反馈结果如图-1所示。
图-1
1.2 方案
在Shell脚本应用中,常见的for循环采用遍历式、列表式的执行流程,通过指定变量从值列表中循环赋值,每次复制后执行固定的一组操作。
for循环的语法结构如下所示:
1.for 变量名 in 值列表
2.do
3. 命令序列
4.done
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:练习for循环基本用法
脚本1,通过循环读取账户文件user.txt,批量创建账户:
1.[root@svr5 ~]# vim for01.sh
2.#!/bin/bash
3.for i in $(cat root/user.txt)
4.do
5. useradd $i
6. echo “123456” | passwd --stdin KaTeX parse error: Expected 'EOF', got '#' at position 25: …8.[root@svr5 ~]#̲ chmod +x for01…(cat /root/ipadds.txt)
4.for IP in $HLIST
5.do
6. ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
7. if [ $? -eq 0 ] ; then
8. echo “Host $IP is up.”
9. else
10. echo “Host $IP is down.”
11. fi
12.done
13.
14.[root@svr5 ~]# chmod +x chkhosts.sh
3)测试、验证脚本
1.[root@svr5 ~]# ./chkhosts.sh
2.Host 192.168.4.5 is up.
3.Host 192.168.4.205 is up.
4.Host 172.16.16.78 is down.
5.Host 202.106.178.234 is down.
2 案例2:使用while循环结构
2.1 问题
本案例要求编写三个使用while循环的脚本程序,分别实现以下目标:
批量添加用户账号:stu1-stu20
批量删除用户账号:stu1-stu20
检测192.168.4.0/24网段,列出不在线的主机地址
2.2 方案
while循环属于条件式的执行流程,会反复判断指定的测试条件,只要条件成立即执行固定的一组操作,直到条件变化为不成立为止。所以while循环的条件一般通过变量来进行控制,在循环体内对变量值做相应改变,以便在适当的时候退出,避免陷入死循环。
while循环的语法结构如下所示:
1.while 条件测试
2.do
3. 命令序列
4.done
2.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:批量添加用户账号stu1-stu20
添加的账号有固定的前缀stu(练习中可自行设置),多个账号从1开始编号,比如stu1、stu2、stu3、……、stu20。—— 编写脚本uaddwhile.sh,实现批量添加这20个用户账号的功能,密码均设为123456。
脚本编写参考如下:
1.[root@svr5 ~]# vim uaddwhile.sh
2.#!/bin/bash
3.PREFIX=“stu” //定义用户名前缀
4.i=1
5.while [ $i -le 20 ]
6.do
7. useradd
P
R
E
F
I
X
{PREFIX}
PREFIXi //添加的用户名为:前缀+编号
8. echo “123456” | passwd --stdin
P
R
E
F
I
X
{PREFIX}
PREFIXi &> /dev/null
9. let i++
10.done
11.[root@svr5 ~]# chmod +x uaddwhile.sh
执行脚本并验证结果:
1.[root@svr5 ~]# ./uaddwhile.sh
2.[root@svr5 ~]# grep ^stu /etc/passwd //检查添加的用户
3.stu1❌531:531::/home/stu1:/bin/bash
4.stu2❌532:532::/home/stu2:/bin/bash
5.stu3❌533:533::/home/stu3:/bin/bash
6.stu4❌534:534::/home/stu4:/bin/bash
7.stu5❌535:535::/home/stu5:/bin/bash
8.… …
步骤二:批量删除用户账号stu1-stu20
针对前面执行uaddwhile.sh脚本批量添加的用户账号,再建立一个批量删除这些账号的脚本udelwhile.sh。结构类似,只要替换为删除相关的操作即可。
脚本编写参考如下:
1.[root@svr5 ~]# vim udelwhile.sh
2.#!/bin/bash
3.PREFIX=“stu”
4.i=1
5.while [ $i -le 20 ]
6.do
7. userdel -r
P
R
E
F
I
X
{PREFIX}
PREFIXi &> /dev/null
8. let i++
9.done
10.[root@svr5 ~]# chmod +x udelwhile.sh
执行脚本并验证结果:
1.[root@svr5 ~]# ./udelwhile.sh
2.[root@svr5 ~]# grep ^stu /etc/passwd //再检查已无相应账号信息
3.[root@svr5 ~]#
步骤三:检测192.168.4.0/24网段,列出不在线的主机地址
1)任务需求及思路分析
要求的是“检测192.168.4.0/24网段,列出不在线的主机地址”。
检测目标是一个网段,其网络部分“192.168.4.”可以作为固定的前缀;而主机部分包括从1~254连续的地址,所以可结合while循环和自增变量进行控制。
2)根据实现思路编写脚本
1.[root@svr5 ~]# vim chknet.sh
2.#!/bin/bash
3.NET=“192.168.4.”
4.i=1
5.while [
i
−
l
e
254
]
6.
d
o
7.
I
P
=
"
i -le 254 ] 6.do 7. IP="
i−le254]6.do7.IP="{NET}$i"
8. ping -c 3 -i 0.2 -W 1 $IP &> /dev/null
9. if [ $? -eq 0 ] ; then
10. echo “Host $IP is up.”
11. else
12. echo “Host $IP is down.”
13. fi
14. let i++
15.done
16.[root@svr5 ~]# chmod +x chknet.sh
3)测试、验证脚本
1.[root@svr5 ~]# ./chknet.sh
2.Host 192.168.4.1 is down.
3.Host 192.168.4.2 is down.
4.Host 192.168.4.3 is down.
5.Host 192.168.4.4 is down.
6.Host 192.168.4.5 is up.
7… …
8.Host 192.168.4.250 is down.
9.Host 192.168.4.251 is down.
10.Host 192.168.4.252 is down.
11.Host 192.168.4.253 is down.
12.Host 192.168.4.254 is down.
3 案例3:基于case分支编写服务脚本
3.1 问题
本案例要求编写myhttpd服务脚本,相关要求如下:
能支持start、stop、restart等控制参数
控制参数通过位置变量$1传入
能通过chkconfig命令来管理此服务
Apache主程序/usr/sbin/httpd
3.2 方案
case分支属于匹配执行的方式,它针对指定的变量预先设置一个可能的取值,判断该变量的实际取值是否与预设的某一个值相匹配,如果匹配上了,就执行相应的一组操作,如果没有任何值能够匹配,就执行预先设置的默认操作。
case分支的语法结构如下所示:
1.case 变量值 in
2.模式1)
3. 命令序列1 ;;
4.模式2)
5. 命令序列2 ;;
6. … …
7.)
8. 默认命令序列
9.Esac
Linux系统的服务脚本默认均位于/etc/init.d/目录下,基本上都采用了case分支结构来识别控制参数。能够执行“ /etc/init.d/服务名 start”或“service 服务名 start”来启动对应的服务,是因为对应的脚本文件能够处理“start”这个位置参数。
3.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:编写脚本文件
脚本编写参考如下:
1.[root@svr5 ~]# vim /etc/init.d/myhttpd
2.#!/bin/bash
3.# chkconfig: 2345 90 10
4.# description: Startup script for http Server. (for Test only)
5.
6.#!/bin/bash
7.case $1 in
8.start)
9. /usr/sbin/httpd
10. echo “我已经启动了”;;
11.stop)
12. kill cat /var/run/httpd/httpd.pid
;; #反引号
13.restart)
14. kill cat /var/run/httpd/httpd.pid
15. sleep 1
16. /usr/sbin/httpd;;
17.status)
18. if [ -f /var/run/httpd/httpd.pid ];then
19. echo “服务正在运行…”
20. else
21. echo “服务已经关闭”
22. fi;;
23.esac
24.) //默认输出脚本用法
25. echo “用法: $0 {start|stop|status|restart}”
26. exit 1
27.esac
28.
29.[root@svr5 ~]# chmod +x /etc/init.d/myhttpd
步骤二:验证、测试脚本
未提供参数,或提供的参数无法识别时,提示正确用法:
1.[root@svr5 ~]# /etc/init.d/myhttpd
2.用法: /etc/init.d/myhttpd {start|stop|status|restart}
3.[root@svr5 ~]# /etc/init.d/myhttpd check
4.用法: /etc/init.d/myhttpd {start|stop|status|restart}
确认可响应status控制参数:
1.[root@svr5 ~]# service myhttpd status
2.服务已经停止。
确认可响应start控制参数,再次检查服务状态:
1.[root@svr5 ~]# service myhttpd start
2.[root@svr5 ~]# service myhttpd status
3.服务正在运行…
确认可响应stop控制参数,再次检查服务状态:
1.[root@svr5 ~]# service myhttpd stop
2.[root@svr5 ~]# service myhttpd status
3.服务已经停止。
上述操作完成后,说明此服务脚本基本上可以使用了。
步骤三:添加myhttpd服务
通过将服务提交给chkconfig管理,方便配置在不同运行级别是否自动运行。
执行以下操作将myhttpd添加为系统服务,并再次检查自启状态:
1.[root@svr5 ~]# chkconfig --add httpd //添加myprog服务
2.[root@svr5 ~]# chkconfig --list httpd //确认添加结果
3.myprog 0:关闭 1:关闭 2:启用 3:启用 4:启用 5:启用 6:关闭
此后,就可以使用chkconfig工具来调整myhttpd服务的自启状态了。比如,以下操作可以将所有自启关闭:
1.[root@svr5 ~]# chkconfig myprog off //将自启设为关闭
2.[root@svr5 ~]# chkconfig --list httpd //确认设置结果
3.myprog 0:关闭 1:关闭 2:关闭 3:关闭 4:关闭 5:关闭 6:关闭
4 案例4:使用Shell函数
4.1 问题
本案例要求编写两个Shell脚本,相关要求如下:
一个funexpr.sh脚本:由用户在执行时提供2个整数值参数,计算这2个整数的加、减、乘、除结果
4.2 方案
在Shell脚本中,将一些需重复使用的操作,定义为公共的语句块,即可称为函数。通过使用函数,可以使脚本代码更加简洁,增强易读性,提高Shell脚本的执行效率
1)函数的定义方法
格式1:
1.function 函数名 {
2. 命令序列
3. … …
4.}
格式2:
1.函数名() {
2. 命令序列
3. … …
4.}
2)函数的调用
直接使用“函数名”的形式调用,如果该函数能够处理位置参数,则可以使用“函数名 参数1 参数2 … …”的形式调用。
注意:函数的定义语句必须出现在调用之前,否则无法执行。
4.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:编写funexpr.sh脚本
1)任务需求及思路分析
用户在执行时提供2个整数参数,这个可以通过位置变量$1、$2读入。
针对给定的两个整数,四则运算可以视为一组操作,可以定义为一个函数,依次负责加减乘除运算并输出结果。
调用函数时,将用户提供的两个参数传递给函数处理。
2)根据实现思路编写脚本文件
1.[root@svr5 ~]# vim funexpr.sh
2.#!/bin/bash
3.myexpr() {
4. echo “$1 + $2 = $[$1+$2]”
5. echo “$1 - $2 = $[$1-$2]”
6. echo “$1 * $2 = $[$1*$2]”
7. echo “$1 / $2 = $[$1/$2]”
8.}
9.myexpr $1 $2
10.
11.[root@svr5 ~]# chmod +x funexpr.sh
3)测试脚本执行效果
1.[root@svr5 ~]# ./funexpr.sh 43 21
2.43 + 21 = 64
3.43 - 21 = 22
4.43 * 21 = 903
5.43 / 21 = 2
6.
7.[root@svr5 ~]# ./funexpr.sh 1234 567
8.1234 + 567 = 1801
9.1234 - 567 = 667
10.1234 * 567 = 699678
11.1234 / 567 = 2
5 案例5:中断及退出
5.1 问题
本案例要求编写两个Shell脚本,相关要求如下:
从键盘循环取整数(0结束)并求和,输出最终结果
跳过1~20以内非6的倍数,输出其他数的平方值,设定退出代码为2
5.2 方案
通过break、continue、exit在Shell脚本中实现中断与退出的功能。
5.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:编写脚本sum.sh
1)编写脚本文件
1.[root@svr5 ~]# vim sum.sh
2.#!/bin/bash
3.while read -p “请输入待累加的整数(0表示结束):” x
4.do
5. [ KaTeX parse error: Expected 'EOF', got '&' at position 12: x -eq 0 ] &̲& break 6. …[SUM+x]
7.done
8.echo “总和是:$SUM”
9.
10.[root@svr5 ~]# chmod +x chkint.sh
步骤二:编写sum.sh脚本文件
1)编写脚本文件
1.[root@svr5 ~]# vim mysum.sh
2.#!/bin/bash
3.i=0
4.while [ $i -le 20 ]
5.do
6. let i++
7. [ $[i%6] -ne 0 ] && continue
8. echo $[i*i]
9.done
10.exit 2
11.[root@svr5 ~]# chmod +x sum.sh