目录
for循环语句
1,for语句的结构
2,for语句应用示例
while循环语句
1,while语句的结构
2,while语句应用示例
until循环语句
1,until循环语句结构
2,until循环语句应用示例
循环语句,作为自动化处理重复任务的利器,在 She11 编程中扮演着至关重要的角色。for 循环、while循环以及 unti1 循环,循环语句是 She11 编程中的核心要素。它不仅能够简化脚本的编写过程,还能提升脚本的执行效率和可维护性。掌握并熟练运用这个工具,将为您的Shel1编程之旅增添无限可能。主要分为以下三类:
for循环:for 循环擅长处理预定义的列表,如批量创建用户账号。
while循环:while 循环则更适用于需要按特定条件重复执行操作的场景。
until循环:until循环则与 while 循环相反,在条件为假时执行循环体。
使用 for 循环语句时,需要指定一个变量及可能的取值列表,针对每个不同的取值重复执行相同的命令序列,直到变量值用完退出循环。在这里,“取值列表”称为for 语句的执行条件,其中包括多个属性相同的对象,需要预先指定(如通讯录、IP黑名单),for循环语句的语法结构如下:
for 变量名 in 取值列表
do
命令序列
done
for 语句的执行流程:首先将列表中的第一个取值赋给变量,并执行 do.done 循环体中的命令序列;然后将列表中的第二个取值赋给变量,并执行循环体中的命令序列…依此类推,直到列表中的所有取值用完,最后将跳至 done 语句,表示结束循环。
在inux 服务器中批量添加相应的用户账号,初始密码均设置为“123456”。其中,员工姓名列表中的账号数量并不固定,而且除了要求账号名称是拼音之外,并无其他特殊规律。
编写一个名为user.txt的员工列表文件,里面存储要创建的账号名字
[root@localhost opt]# cat /user.txt
zhangsan
lisi
wangwu
zhaoliu
编写一个名为for.sh的shell脚本,从user.txt文件中读取各用户名称,重复执行添加用户,设置初始密码的相关操作。
[root@localhost opt]# cat for.sh
#!/bin/bash
add=`cat /user.txt`
for UNAME in $add
do
useradd $UNAME
echo "123456" | passwd --stdin $UNAME &>/dev/null ##初始密码设置为123456
done
[root@localhost opt]# chmod +x for.sh
验证测试结果
[root@localhost opt]# bash for.sh
[root@localhost opt]# tail -4 /etc/passwd ##查看用户信息后4行
zhangsan:x:1000:1000::/home/zhangsan:/bin/bash
lisi:x:1001:1001::/home/lisi:/bin/bash
wangwu:x:1002:1002::/home/wangwu:/bin/bash
zhaoliu:x:1003:1003::/home/zhaoliu:/bin/bash
如果要删除创建的用户也可以使用脚本来执行
[root@localhost opt]# cat fordel.sh
#!/bin/bash
add=`cat /user.txt`
for UNAME in $add
do
userdel -r $UNAME &>/dev/null ##只需将useradd更改为userdel -r
done
[root@localhost opt]# chmod +x fordel.sh
验证脚本编写结果
[root@localhost opt]# bash fordel.sh
[root@localhost opt]# tail -4 /etc/passwd ##再次查看发现已被删除
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
unbound:x:996:993:Unbound DNS resolver:/etc/unbound:/sbin/nologin
chrony:x:995:992::/var/lib/chrony:/sbin/nologin
检査其中各主机的 ping 连通性,输出各主机是否启动、关闭。其中,服务器的数量并不固定,各服务器的IP地址之间也无特殊规律,可先指定 IP 地址列表文件 ip.txt。然后编写一个名为 ping.sh的Shel1 脚本,从 ip.txt 文件中读取各服务器的 IP 地址,重复执行 ping 连通性测试,并根据测试结果输出相应的提示信息。
[root@localhost opt]# cat /ip.txt ##编写ip地址测试的列表文件
192.168.10.102
172.16.16.1
192.168.10.111
172.16.16.220
127.0.0.1
编写名为ping.sh的脚本
[root@localhost opt]# cat ping.sh
#!/bin/bash
ping=$(cat /ip.txt)
for ip in $ping
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 ip down."
fi
done
[root@localhost opt]# chmod +x ping.sh
对ping.sh脚本进行测试
[root@localhost opt]# bash ping.sh
Host 192.168.10.102 is up.
Host 172.16.16.1 ip down.
Host 192.168.10.111 ip down.
Host 172.16.16.220 ip down.
Host 127.0.0.1 is up.
do…done循环体内嵌套使用了 if 条件选择语句,用来针对不同 P 地址的测试结果进行判断,并输出相应的提示信息。嵌套可以理解为镶嵌、套用,就是在已有的语句、函数中在多加一个或多个语句、函数等。实际上,if 语句、for 语句及其他各种 She11 脚本语句都是可以嵌套使用的,后续课程中将不再重复说明。
[root@localhost /]# cat a.sh
for i in {1..254}
do
ping -c 2 -i 0.3 -W 1 192.168.10.$i &>/dev/null
#每隔0.3秒ping一次,一共ping2次,并以1毫秒为单位设置ping的超时时间
if [ $? -eq 0 ];
then
echo "192.168.10.$i is up"
else
echo "192.168.10.$i is down"
fi
done
[root@localhost /]# chmod +x a.sh
[root@localhost /]# cat d.sh
for i in `seq 9`
do
for j in `seq $i`
do
echo -n "$j*$i=$[i*j] "
done
echo
done
[root@localhost /]#chmod +x d.sh
[root@localhost /]# . d.sh
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
使用 while循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。在脚本应用中,应该避免出现死循环的情况,否则后边的命令操作将无法执行。因此,循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环,格式如下:
while 条件测试操作
do
命令序列
done
while 语句的执行流程:首先判断 while 后的条件测试操作结果,如果条件成立,则执行 do..done循环体中的命令序列;返回 while 后再次判断条件测试结果,如果条件仍然成立,则继续执行循环体:再次返回到 while 后,判断条件测试结果!……如此循环,直到 while 后的条件测试结果不再成立为止,最后跳转到 done 语句,表示结束循环。
如果需要批量添加用户账号,这些用户名称中包含固定的前缀字串,按照数字顺序依次进行编号,账号数量往往也是固定的,例如 添加10个用户,名称为name1,name2......name10。
[root@localhost opt]# cat while.sh
#!/bin/bash
while="name"
i=1
while [ $i -le 10 ]
do
useradd ${while}$i
echo "123456" | passwd --stdin ${while}$i &>/dev/null
let i++
done
[root@localhost opt]# chmod +x while.sh
使用变量 i 来控制用户名称的编号,初始赋值为 1,并且当取值大于 10 时终止循环。在循环体内部,通过语句“let i++”(等同于 i=`expr $i +1`)来使变量 i 的值增加 1,因此当执行第一次循环后 i 的值将变为 2,执行第二次循环后 i 的值将变为 3,…,依此类推。
[root@localhost opt]# cat /etc/passwd | grep name
name1:x:1000:1000::/home/name1:/bin/bash
name2:x:1001:1001::/home/name2:/bin/bash
name3:x:1002:1002::/home/name3:/bin/bash
name4:x:1003:1003::/home/name4:/bin/bash
name5:x:1004:1004::/home/name5:/bin/bash
name6:x:1005:1005::/home/name6:/bin/bash
name7:x:1006:1006::/home/name7:/bin/bash
name8:x:1007:1007::/home/name8:/bin/bash
name9:x:1008:1008::/home/name9:/bin/bash
name10:x:1009:1009::/home/name10:/bin/bash
如果想要删除脚本创建的用户,只需要修改以下部分。
[root@localhost opt]# cat whiledel.sh
#!/bin/bash
while="name"
i=1
while [ $i -le 10 ]
do
userdel -r ${while}$i &>/dev/null ##将useradd改为userdel -r
let i++
done
[root@localhost opt]# chmod +x whiledel.sh
查看删除的结果
[root@localhost opt]# tail -5 /etc/passwd ##发现没有关于name的用户
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
unbound:x:996:993:Unbound DNS resolver:/etc/unbound:/sbin/nologin
chrony:x:995:992::/var/lib/chrony:/sbin/nologin
针对上述要求,主要设计思路如下:通过环境变量 RANDOM 可获得一个小于 216的随机整数,计算其与 1000 的余数即可获得 ~999 的随机价格;反复猜测操作可以通过以 true 作为测试条件的while 循环实现,当用户猜中实际价格时终止循环;判断猜测价格与实际价格的过程采用 if 语句实现,嵌套在 while 循环体内;使用变量来记录猜测次数。
[root@localhost opt]# cat while2.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 opt]# chmod +x while2.sh
测试while2.sh脚本的执行结果
[root@localhost opt]# bash while2.sh
商品价格范围0-999,请输入一个价格猜猜看
请输入你猜测的价格数目:500
太高了
请输入你猜测的价格数目:300
太低了
请输入你猜测的价格数目:400
太高了
请输入你猜测的价格数目:350
太低了
请输入你猜测的价格数目:360
太高了
请输入你猜测的价格数目:355
太高了
请输入你猜测的价格数目:3354
太高了
请输入你猜测的价格数目:354
太高了
请输入你猜测的价格数目:353
太高了
请输入你猜测的价格数目:352
太高了
请输入你猜测的价格数目:351
恭喜你答对了,实际价格是351
你总共猜测了11次
unti1 循环与 while 循环类似,while 循环能实现的脚本 unti1 同样也可以实现,但区别是while循环在条件为真是继续执行循环,而 unti1 则是在条件为假时执行循环,格式如下:
until 条件测试操作
do
命令序列
done
unti1 语句的执行流程: 首先判断 unti1 后的条件测试操作结果,如果条件不成立,则执行 do..done循环体中的命令序列;返回 unti1 后再次判断条件测试结果,如果条件仍然不成立,则继续执行循环体;再次返回到 unti1 后,判断条件测试结果.…如此循环,直到 unti1 后的条件测试结果成立为止,最后跳转到 done 语句,表示结束循环。
计算从 1 到58 的和,从1开始相加,采用循环的方式,每次循环后加 1,将得到的值加入计算的和中,数字运算采用的是 let 方式,直到加到 50 为止.。
[root@localhost opt]# cat until.sh
#!/bin/bash
i=0;s=0
until [ $i -eq 50 ]
do
let "i=$i+1";let "s=$s+$i" ##在i的值小于50之前,每次循环i的值加1,并且求出s的值
done
echo 'sum(1..50)=' $s
[root@localhost opt]# chmod +x until.sh
[root@localhost opt]# bash until.sh ##验证脚本编写结果
sum(1..50)= 1275
[root@localhost opt]# cat until2.sh
#!/bin/bash
#检查参数数量是否足够
if [ $# -lt 2 ]; then
echo "Usage: $0 ..."
exit 1
fi
#提取消息,消息为最后一个参数
message="${$#}"
#遍历除最后一个参数外的所有用户名
for username in "${@:1:$#-1}"; do
#检查用户是否为系统内用户
if ! grep -q "^$username:" /etc/passwd; then
echo "$username is not a valid user on this system."
continue
fi
#持续检查用户是否登陆
while ! who | grep -q "$username"; do
echo "$username is not logged on. Waiting for the user to log in..."
sleep 60
done
#用户已登陆,发送信息
echo "Sending message to $username..."
write "$username" <
对刚刚编写的until2.sh脚本进行测试
[root@localhost opt]# bash until2.sh root hello
发送给root自己,消息为hello
[root@localhost opt]# bash until2.sh zhangsan hello
发送给zhangsan用户,消息为hello