shell 循环
- for循环
- 案例1:
- 案例2:
- 案例3:
- 案例4:
- 案例5:
- 案例6:
- 案例7:
- 案例8:
- 案例9:
- 案例10:
- 案例11:
for循环
什么是循环
重复执行一段代码
-
比如批量创建100个用户,可以用到循环。
循环的目的是为了简化代码,提高代码的重复利用率,提高程序效率。 -
什么是for循环
- for循环->条件循环,
- for循环 循环的次数和给予的条件是成正比的,比如给了5个条件,那么循环就只会循环5次
-
for循环的语法
-
for 变量名 in 取值列表 do循环体需要执行的动作 done
示例
for i in 1 2 3 4 5doecho 12345done
脚本执行效果
类C语言风格的写法
for ((i=0;i<9;i++))doecho "num is $i"done
脚本执行效果
案例1:
输出1-到15之间的数字
#!/bin/bashfor i in {1..15}
doecho num is $i
done
脚本执行效果
案例2:
第一列输出1-9之间的升序,然后第二列输出9-1的降序
整数运算:let
+ - * / % , **次方
例:let sum=2**4 ;echo $sum
自增自减:let i++ 常用来进行运算统计
a=$[ $a -1 ] #让a变量进行自减 let a--
b=$[ $b +1 ] #让b变量进行自增 let b++
#!/bin/basha=9
b=1for i in {1..9}
doecho "num is $b $a"let a--let b++
done
脚本执行效果
案例3:
批量探测某个网段的主机存活状态,将存活的主机存入ipok.txt文件中,不存活的主机存入ipnok.txt。
{程序}&
表示将程序放到后台并行执行,如需等待程序执行完毕再进行下面内容,需要加wait
#!/bin/bashfor ip in {1..254} #设定IP地址的主机位范围
do
{ip_addr=192.168.3.$ip #设定一个变量用于接收每个IP地址ping -c1 -w1 $ip_addr &>/dev/null #检测主机的存活if [ $? -eq 0 ];then #上一条命令执行返回的结果为0,说明地址存活,存活主机IP输入到ipok.txtecho "${ip_addr} is ok" >>ipok.txtelse #不存活主机IP输入到ipnok.txtecho "${ip_addr} not ok" >>ipnok.txtfi
}&done
脚本执行效果
查看存活的主机IP地址
查看不存活的主机IP地址
案例4:
判断主机存活状态,判断三次,如果三次失败则失败。
思路梳理:
ping网段内所有的主机
如果通,则不管
如果不通,则进入另一个循环,而另一个循环需要循环3次。
如果在第二次循环时通了,则退出第二层循环,回到第一层循环中。
#!/bin/bashfor ip in {1..254} #第一层循环
do{ip_addr=192.168.3.$ipping -c1 -w1 $ip_addr &>/dev/nullif [ $? -eq 0 ];then #如果第一次ping通了,就输入到ipok1.txtecho "$ip_addr is ok">> ipok1.txtelse #第一次ping不通,就进入第二层循环for i in {1..3}doping -c1 -w1 $ip_addr &>/dev/nullif [ $? -eq 0 ];then #第二次ping通就跳出循环echo "探测 $ip_addr $i 次成功,IP存活" >> ipok1.txtbreakelse #echo "探测 $ip_addr $i 次失败,IP不存活">> ipnok1.txtfidonefi}&
done
脚本执行效果:
案例5:
现在有一个ip.txt的文件,里面有很多IP地址。
还有一个port.txt的文件,里面有很多端口号。
现在希望对ip.txt的每个IP地址进行端口的探测,探测的端口号来源于port.txt文件中,最后将开放的端口和IP保存到一个ipportok.txt文件。
这里用到一个工具 nc
nc可以支持测试linux的tcp和udp端口,而且也经常被用于端口扫描
1) -l
用于指定nc将处于侦听模式。指定该参数,则意味着nc被当作server,侦听并接受连接,而非向其它地址发起连接。2) -p
暂未用到(老版本的nc可能需要在端口号前加-p参数)3) -s
指定发送数据的源IP地址,适用于多网卡机4) -u
指定nc使用UDP协议,默认为TCP5) -v
输出交互或出错信息,新手调试时尤为有用6)-w
超时秒数,后面跟数字7)-z
表示zero,表示扫描时不发送任何数据
ip.txt
port.txt
#!/bin/bashfor ip in $(cat ip.txt) #第一层循环,先获取到IP地址
dofor port in $(cat port.txt) #获取到一个IP地址后,进入第二层循环,对该IP端口逐个扫描donc -zv -w 1 $ip $port &>/dev/null if [ $? -eq 0 ];thenecho "$ip $port is ok" >> ipportok.txtfidone
done
脚本执行效果
案例6:
获取系统的所有用户并输出。
效果如下:
This is 1 user: root
This is 2 user: bin
This is 3 user: daemon
This is 4 user: adm
#!/bin/bash
num=1for user in $(cat /etc/passwd|awk -F ":" '{print $1}')
do echo "this is $num user: $user"let num++
done
脚本执行效果
案例7:
批量创建10个用户,比如输入tst则会创建tst1-10。
1.提示用户输入名称,判断用户是否已存在,不存在再进行创建操作
2.需要循环10次。
#!/bin/bashread -p "输入用户名前缀:" userfor i in {1..10}
do id ${user}$i &>/dev/nullif [ $? -eq 0 ];thenecho "$user$i already exists"else useradd ${user}$i && \echo "${user}$i 创建成功"fi
done
脚本执行效果:
案例8:
批量创建用户脚本,需要用户输入创建的用户数量,以及需要用户输入创建的前缀。
例如:前缀wang,个数10,代表创建wang1~wang10,总共10个用户。
1.提示用户要创建的前缀。(英文)
2.提示用户需要创建的个数(整数)
3.询问是否创建这个用户。
yes:开始通过循环创建用户
no:退出程序。
#!/bin/bashsource /etc/init.d/functionsread -p "输入纯英文用户前缀:" qz
if [[ ! $qz =~ ^[a-z]+$ ]];thenecho "输入纯英文"exit
firead -p "输入纯数字用户个数:" nu
if [[ ! $nu =~ ^[0-9]+$ ]];thenecho "输入纯数字"exit
firead -p "是否创建 ${qz}1 ~ ${qz}$nu [ yes | no ]" actioncase $action inyes)for i in $(seq $nu)doid ${qz}$i &>/dev/nullif [ $? -eq 0 ];thenaction "${qz}$i 已存在" /bin/falseexitelseuseradd ${qz}$i && \action "${qz}$i 创建成功" /bin/truefidone;;no)exit;;
esac
案例9:
批量创建用户脚本,需要用户输入创建的用户数量(必须是整数),同时还需要用户输入前缀(前缀不能为空)。例如:前缀qq,个数6,代表创建qq1~qq6,总共6个用户。
其实就是在上一个案例的基础之上,添加一个不能为空的判断
#!/bin/bashsource /etc/init.d/functionsread -p "输入纯英文用户前缀:" qzif [ -z $qz ];then #-z字符串长度为0则为真echo "输入不能为空"exit
fiif [[ ! $qz =~ ^[a-z]+$ ]];thenecho "输入纯英文"exit
firead -p "输入纯数字用户个数:" nu
if [[ ! $nu =~ ^[0-9]+$ ]];thenecho "输入纯数字"exit
firead -p "是否创建 ${qz}1 ~ ${qz}$nu [ yes | no ]" actioncase $action inyes)for i in $(seq $nu)doid ${qz}$i &>/dev/nullif [ $? -eq 0 ];thenaction "${qz}$i 已存在" /bin/falseelseuseradd ${qz}$i && \action "${qz}$i 创建成功" /bin/truefidone;;no)exit;;
esac
脚本执行效果
案例10:
循环批量创建用户,需要填入用户的数量、用户的前缀、用户的统一密码(使用read、case、for语句)
在上一个案例的基础上,添加了创建密码的操作
#!/bin/bashsource /etc/init.d/functionsread -p "输入纯英文用户前缀:" qzif [ -z $qz ];thenecho "输入不能为空"exit
fiif [[ ! $qz =~ ^[a-z]+$ ]];thenecho "输入纯英文"exit
firead -p "输入纯数字用户个数:" nu
if [[ ! $nu =~ ^[0-9]+$ ]];thenecho "输入纯数字"exit
firead -p "是否创建 ${qz}1 ~ ${qz}$nu [ yes | no ]" actioncase $action inyes)for i in $(seq $nu)doid ${qz}$i &>/dev/nullif [ $? -eq 0 ];thenaction "${qz}$i 已存在" /bin/falseelseuseradd ${qz}$i && \echo "123456" |passwd --stdin ${qz}$i &>/dev/nullaction "${qz}$i 创建成功" /bin/truefidone;;no)echo "拜拜!"exit;;
esac
脚本执行效果:
输入用户名密码进行登录测试
案例11:
现在需要随机密码。然后将创建的用户名以及对应的密码,写到一个username.txt文件中。
思路梳理:
1.随机密码如何弄?
mkpasswd -l 8 -d 2 -c 2 -C 2 -s 2
2.将创建的用户名称与密码写入对应的文件中即可。
随机密码获取:
mkpasswd命令
默认是没有安装mkpasswd的,mkpasswd命令使用前需要安装expect包,
yum install -y expect
然后就可以使用mkpasswd
命令了
语法格式:mkpasswd [参数] [用户]常用参数:-c 定义在密码中小写字母字符的最小数目,默认值是2
-C 定义在密码中大写字母字符的最小数目,默认值是2
-s 定义在密码中特殊字符的最小数目,默认值是1
-p 指定程序来设置密码。默认情况下,如果存在使用/etc/yppasswd,否则使用/bin/passwd
-d 定义密码的最小数目,默认值是2
-l 定义口令的长度,默认值为9
-v 导致密码设置互动可见例如:
为用户更改随机密码
echo mkpasswd -l 8 | passwd --stdin test
echo
-n:不输出换行符,而是连续输出多个消息-e:启用转义字符,可以使用一些特殊的字符序列来输出一些特殊的字符\n:换行符\t:制表符\:反斜线\b:退格符-E:禁用转义字符-s:将空格当成分隔符,去掉多余的空格
#!/bin/bashsource /etc/init.d/functionsread -p "输入纯英文用户前缀:" qzif [ -z $qz ];thenecho "输入不能为空"exit
fiif [[ ! $qz =~ ^[a-z]+$ ]];thenecho "输入纯英文"exit
firead -p "输入纯数字用户个数:" nu
if [[ ! $nu =~ ^[0-9]+$ ]];thenecho "输入纯数字"exit
firead -p "是否创建 ${qz}1 ~ ${qz}$nu [ yes | no ]" actioncase $action inyes)for i in $(seq $nu)douserpasswd=$(mkpasswd -l 8 -d 2 -c 2 -C 2 -s 2) #按照要求生成随机密码id ${qz}$i &>/dev/nullif [ $? -eq 0 ];thenaction "${qz}$i 已存在" /bin/falseelseuseradd ${qz}$i && \echo $userpasswd |passwd --stdin ${qz}$i &>/dev/nullaction "${qz}$i 创建成功" /bin/trueecho -e "${qz}$i \t $userpasswd" >>user_passwd.txt #echo -e:启用转义字符 \t制表符fidone;;no)echo "拜拜!"exit;;
esac
脚本执行效果: