shell循环
shell循环
循环的分类
循环名称 | 循环的含义 | 使用场景 |
---|---|---|
while循环 | 当型循环 | 死循环/有条件的循环/一行一行的读取的文件 |
do until | 直到型循环 | 没啥用. |
for 循环 | 通用型 | 很多场景都可以使用 |
循环语法
# while 循环
while <条件表达式>;do
cmd1
cmd2
cmd3
done
while <条件表达式>
do
cmd1
cmd2
cmd3
done
# 死循环
while true;do
echo 'hei hei hei'
done
while [ 1 -eq 1 ];do
echo 'hei hei hei'
done
while :;do
echo 'hei hei hei'
done
使用while循环模拟for循环seq
n=1
while [ $n -le 10 ];do
echo $n
((n++))
done
for n in `seq 10`;do
echo $n
done
使用while循环实现1+100
n=1
num=0
while [ $n -le 100 ];do
((num=num+n))
((n++))
done
echo $num
# 其他方法
[root@m01 ~]# echo {1..100}|tr ' ' '+'|bc
[root@m01 ~]# seq -s + 100|bc
[root@m01 ~]# seq 100|awk '{m=m+$1}END{print m}'
[root@m01 ~]# awk 'BEGIN{for(i=1;i<=100;i++)sum=sum+i;print sum}'
for循环
语法一
无法指定循环次数,变量表达式中有多少内容就循环多少次
for i in 1 2 3 4;do
echo $i
done
for i in 变量表达式
do
cmd1
cmd2
done
变量表达式:
- 可以是文件中的内容(按空格循环)
- 可以是序列命令的内容
- 可以是数组中的内容
- 可以是以空格为分隔符的字符串
# 文件内容
for i in `cat 1.txt`;do
echo $i
done
for i in ${cat 1.txt};do
echo $i
done
# 序列内容
for i in `seq 10`;do
echo $i
done
# 数组
array=(cjk dsb wls)
for i in ${array[*]};do
echo$i
done
# 以空格为分隔符
name="cjk dsb wls"
for i in $name;do
echo $i
done
语法二
指定循环的次数
for ((i=1;i<=10;i++));do
echo $i
done
死循环
for (( ; ; ));do
echo 123
done
循环的控制语句
Break
# break(跳出循环)
break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。
n=0
while [ $n -lt 10 ];do
((n++))
if [ $n -eq 5 ];then
break
fi
echo $n
done
Continue
# continue(跳出循环)
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
n=0
while [ $n -lt 10 ];do
((n++))
if [ $n -eq 5 ];then
continue
fi
echo $n
done
for循环读取文件
# for 循环读取文件
for txt in `cat 1.txt`;do
echo $txt
done
while循环读取文件
# while 读取文件
1.
exec < 1.txt
while read line;do
echo '-------'
echo $line
done
2.
while read line;do
echo '-------'
echo $line
done <1.txt
3.
cat 1.txt|while read line;do
echo '-------'
echo $line
done
while练习
写一个脚本,读取下面文件内容,并算出所有人年龄总和
[root@zabbix01 ~]# cat student.txt
曾老湿 18
苍井空 20
武藤兰 33
天海翼 32
西野翔 18
# 方法一
sum=0
while read line;do
age=`echo $line|awk '{print $2}'`
((sum+=age))
done < age.txt
echo $sum
# 方法二
exec < age.txt
sum=0
while read line;do
age=`echo $line|awk '{print $2}'`
((sum+=age))
done
echo $sum
案例一
日志分析案例
写一个shell脚本,防止DDOS攻击,先分析日志,监控某一个IP并发连接数,若短时内PV达到100阈值,则调用防火墙命令,封掉该IP。
可以分析nginx日志或者查看当前网络连接数 ss -ant 或者 netstat -ant
这里使用一个生产的日志 netstat.log
# 作业
grep -w 'tcp' /root/netstat.log|awk '{print $5}'|sort|uniq -c|sort -r|while read line;do
test=`echo ${line}|awk '{print $1}'`
ip=`echo ${line}|awk '{print $2}'|awk -F : '{print $1}'`
if [ $test -gt 100 ];then
firewall-cmd --add-source=${ip} --zone=drop
fi
done
案例二
在指定目录下,通过随机10个小写字母,然后生成一个文件名为: 随机字母_zls.txt 的文件
# 生成随机内容的方法
## 方法一:
[root@zabbix01 ~]# openssl rand -base64 10
UUBtKUvUkEfcEw==
## 方法二:
[root@zabbix01 ~]# echo $((RANDOM))|md5sum
## 方法三:
[root@zabbix01 ~]# date +%N|md5sum
3fd3a5c57def5f89481e1961fceb13e8
## 方法四:
tr -cd 'a-zA-Z0-9'</dev/urandom|head -c 10
# 作业
random=`tr -cd 'a-z'</dev/urandom|head -c 10`
mkdir /opt/${random}_zls.txt
案例三
# 提示一:变量子串方法
# 提示二:sed awk方法
# 提示三:命令拼接
# 提示四:rename
rename zls.txt cls.TXT /root/*.txt
#!/bin/bash
for name in `ls -1 /abc`;do
#mv /abc/${name%.*}.yml /abc/${name%.*}.j2
mv /abc/$name /abc/${name//j2/yml}
done
案例四
创建100个系统用户,生成随机密码
并将用户名和密码保存到文件中
用户名:密码
# 作业
for i in `seq 100`;do
useradd user$i
pass=`sh ./l.sh`
echo "user$i:$pass" >> /tmp/password
echo "----------" >> /tmp/password
echo ${pass}|passwd --stdin user$i
done
案例五
现在我们要模拟黑客,来扫描,指定网段内存活的主机
# 作业
[root@m01 ~]# cat dk.sh
#!/bin/bash
# File Name: __dk.sh__
# Version: __v1.1__
# Author: __Driverwang__
# Mail: __2794552827@qq.com__
# Blog: __https://blog.driverzeng.com__
# DateTime: __2022-07-25 17:45__
. /etc/init.d/functions
#for n in `seq 254`;do
# ping -c 1 10.0.0.$n
#done
for n in `seq 254`;do
{
ping -c1 -W1 -i1 10.0.0.$n &>/dev/null
if [ $? -eq 0 ];then
action 10.0.0.$n /bin/true
{
for port in `seq 65535`;do
port=`echo ' '|telnet 10.0.0.${n} ${port} 2>/dev/null |grep 'Connected'|wc -l`
if [ $port -ne 0 ];then
action "${port} 端口已存在" /bin/true
fi
usleep 300
done
} &
fi
} &
usleep 300
done