shell编程与循环语句(for语句 while语句 untli语句 IFS分隔符)

171 阅读4分钟

for语句的结构

读取不同的变量值,用来逐个执行同一组命令

QQ截图20220830163841.png

[root@localhost ~]# for num in 1 2 3 4 5 6
> do
> echo $num
> done
1
2
3
4
5
6
[root@localhost ~]# for i in $(seq 1 10)
> do
> echo $i
> done
1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# echo {1..10..2}
1 3 5 7 9
[root@localhost ~]# seq 1  5
1
2
3
4
5
[root@localhost ~]# seq 1 2 10
1
3
5
7
9

for语句应用

批量添加用户并改密码

[root@localhost ~]# vim userlist
wangwu
shangsan
zhuliu
laoba
laoliu
liangliang

[root@localhost ~]# cat userlist
wangwu
shangsan
zhuliu
laoba
laoliu
liangliang


[root@localhost ~]# vim demo1.sh
#!/bin/bash
#批量添加用户
#用户名存放在users.txt文件中,每行一个
#初始密码均为123456

for username in $(cat /root/userlist)
do
  useradd $username
  echo 123456 | passwd --stdin $username &> /dev/null
  echo "用户${username}添加完毕"
done

[root@localhost ~]# sh demo1.sh
用户wangwu添加完毕
用户shangsan添加完毕
用户zhuliu添加完毕
用户laoba添加完毕
用户laoliu添加完毕
用户liangliang添加完毕


[root@localhost ~]# tail /etc/passwd
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
w:x:1000:1000:w:/home/w:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
wangwu:x:1001:1001::/home/wangwu:/bin/bash
shangsan:x:1002:1002::/home/shangsan:/bin/bash
zhuliu:x:1003:1003::/home/zhuliu:/bin/bash
laoba:x:1004:1004::/home/laoba:/bin/bash
laoliu:x:1005:1005::/home/laoliu:/bin/bash
liangliang:x:1006:1006::/home/liangliang:/bin/bash
#!/bin/bash
#判断用户是否已经存在,用户不存在的添加用户

for username in $(cat /root/userlist)
do
 id $username &> /dev/null
 if [ $? -eq 0 ];then
    echo "$username 已存在"
 else

   useradd $username
   echo 123465 | passwd --stdin $username &> /dev/null
   echo "用户${username}添加完成"
 fi
done


[root@localhost ~]# sh demo2.sh
wangwu 已存在
shangsan 已存在
zhuliu 已存在
laoba 已存在
laoliu 已存在
liangliang 已存在
用户jiujiu添加完成
用户baibai添加完成
用户xuebi添加完成
用户kele添加完成

检查主机在线情况

#!/bin/bash
#检查85网段的所有主机在线情况

for IP in 192.168.85.{10..50..10}
do
 ping -c 3 -i 0.5 -w 2 $IP &> /dev/null
 if [ $? -eq 0 ];then
    echo "$IP is online"
  else
    echo "$IP is offline"
  fi
done

[root@localhost ~]# sh demo11.sh
192.168.85.10 is online
192.168.85.20 is offline
192.168.85.30 is offline
192.168.85.40 is offline
192.168.85.50 is offline

多线程查看

#!/bin/bash
#shell多线程脚本

for IP in {10..70}
do
 {
  ping -c 3 -i 0.5 -W 2 192.168.85.$IP &> /dev/null
  if [ $? -eq 0 ];then
    echo "192.168.85.$IP is online" >> /data/ping.txt
  else
    echo "192.168.85.$IP is offlien"
  fi
 }&
#{....}&代表的是将每个循环操作的进程放到后台运行,且后台进程不区分前后顺序
done

#wait命令用于等待上面所有后台进程都执行完毕后再执行后面的shell语句
wait

cat /data/ping.txt

while语句结构

重负测试某个条件,只要条件成立则反复执行 QQ截图20220830220943.png 列子:

[root@localhost ~]# while [ $i -le 10 ]
> do
> echo $i
> let i++
> done
1
2
3
4
5
6
7
8
9
10

while语句应用

批量添加用户并添加密码

#!/bin/bash
#批量添加用户
#用户名以stu开头,按数字顺序进行编号
#一共添加20个用户,如stu1 stu2 ...... stu20
#初始密码均为123456

i=1
while [ $i -le 20 ]
do
 useradd stu$i
 echo 123456 | passwd --stdin stu$i
 echo "用户 stu$i 添加成功"
 let i++
done

QQ截图20220830223807.png

#!/bin/bash
#猜商品游戏
#通过变量RANDOM获取随机数
#提示用户猜测并技术次数,猜中后退出循环


#获取0-999的随机数
NUM=$[RANDOM % 1000]
#定义变量i为循环条件的变量
i=1
#定义变量a记录猜测次数的变量
a=0
while [ $i -eq 1 ]
do
#获取用户输入的数值
 read -p "请输入你猜测的价格(0-999):" price
#使用随机数和用户输入的数值比较,并且每次比较记录猜测次数,如果数值不等则会一直在死>循环中重负猜测
 if [ $price -eq $NUM ];then
    echo "恭喜!你猜对了!....."
    let a++
    let i++
  elif [ $price -gt $NUM ];then
    echo "不好意思,你猜高了....."
    let a++
  elif [ $price -lt $NUM ];then
    echo "不好意思,你猜低了....."
    let a++
  fi
done
#输出猜测的总次数
echo "你一共猜了 $a 次。"

QQ截图20220830232740.png

nutil语句的结构

重复测试某个条件,只要条件不成立则反复执行 QQ截图20220831084047.png

[root@localhost ~]# until [ $i -gt 10 ]
> do
> echo $i
> let i++
> done

1
2
3
4
5
6
7
8
9
10

监控登录人数

#!/bin/bash
#使用until循环来监控系统的登录人数,当人数高于3人时每10秒提醒警告信息


users=$(who | wc -l)
until [ $users -le 3 ]
do
  echo "当前登录人数为 $users ,大于3人,请注意!!"
  sleep 10
  users=$(who | wc -l)
done


[root@localhost ~]# . demsh
当前登录人数为 6 ,大于3人,请注意!!
当前登录人数为 6 ,大于3人,请注意!!
当前登录人数为 5 ,大于3人,请注意!!

求和值

#!/bin/bash
#计算1~50的和值
#通过循环累加的方式计算1~50的和值

sum=0
i=1
until [ $i -gt 50 ]
do
  sum=$[sum + i]
  let i++
done
  echo $sum

[root@localhost ~]# sh demo16.sh
1275

echo的特殊用法大全

命令含义
echo -n表示不换行输出
echo -e输出转义字符,将转义后的内容输出到屏幕上

常用的转义字符

字符含义
\b转义后相当于按退格键(backspace),但前提是"\b"后面存在字符;"\b"表示删除前一个字符,"\b\b"表示删除前两个字符。
\c不换行输出,在"\c"后面不存在字符的情况下,作用相当于echo -n;但是当"\c"后面仍然存在字符时,"\c"后面的字符将不会被输出。
\n换行,被输出的字符从"\n"处开始另起一行
\f换行,但是换行后的新行的开头位置连接着上一行的行尾
\v与\f相同
\t转以后表示插入tab,即横向制表符
\r光标移至行首,但不换行,相当于使用"\r"以后的字符覆盖" \r"之前同等长度的字符;但是当"\r"后面不存在任何字符时,"\r"前面的字符不会被覆盖
\ \表示插入" \ "本身
[root@localhost ~]# echo -e  "abc\n123"
abc
123
[root@localhost ~]# echo -e "ancf\v123"
ancf
    123
[root@localhost ~]# echo -e "ancf\f123"
ancf
    123

截取字符串的长度(分片)

${变量名:下标:长度}

[root@localhost ~]# i=123456789
[root@localhost ~]# echo $i
123456789
[root@localhost ~]# echo ${i:3:2}
45
[root@localhost ~]# echo ${i:3:3}
456
[root@localhost ~]# echo ${i:5:1}
6

字符串长度

${#变量名}

[root@localhost ~]# name=wangwu
[root@localhost ~]# echo $name
wangwu
[root@localhost ~]# echo ${#name}
6

随机获得8位数的密码

#!/bin/bash

STR="abcdefghijklmnopqrxtuvwxyzABCDEVFHIJKLMNOPQRXTUVWXYZ123456789"
sum=''
for ((i=1; i<=8; i++))
do
   length=${#STR}
   num=$[RANDOM % length]
   value=${STR:num:1}
   sum+=$value
done
echo "$sum"

[root@localhost ~]# sh demo17.sh
KZ9dLfnZ
[root@localhost ~]# sh demo17.sh
Ele1yaDl

IFS字段分隔符

造成这个问题的原因是特殊的环境变量IFS,叫作内部字段分隔符( internal field separator)。IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下, bash shell会将下列字符当作字段分隔符:

  1. 空格
  2. 制表符
  3. 换行符 如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明了列表中一个新数据字段的开始。在处理可能含有空格的数据(比如文件名)时,这会非常麻烦,就像你在上一个脚本示例中看到的。 要解决这个问题,可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段分隔符的字符。例如,如果你想修改IFS的值,使其只能识别换行符,那就必须这么做:IFS=$'\n' 将这个语句加入到脚本中,告诉bash shell在数据值中忽略空格和制表符。

默认包括 空格,制表符,换行符 set | grep IFS IFS=$'\T\N'

修改成只换行

IFS=$'\n'

[root@localhost ~]# set | grep IFS
IFS=$' \t\n'
    local i IFS='
    local i IFS=" "'
    local i IFS=" "'
    local i IFS='
    local i IFS='
            local c i=0 IFS='
    local IFS='
    local IFS='
    local option option2 i IFS='
    IFS='
        local IFS='
        local IFS='
        local IFS='
        local IFS='
    local IFS='
        local IFS='
    local i IFS='
    local IFS='
            local i c='' IFS='
        local OIFS=$IFS IFS='
        IFS=$OIFS;
                local IFS='
                    local IFS='
                    local IFS='
    local IFS='
#!/bin/bash
OLO_IFS=$IFS
IFS=$IFS':'
for i in $(echo $PATH)
do
  echo $i
done

IFS=$OLO_IFS

[root@localhost ~]# sh demo20.sh
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin

换位

需要增加一位来更换

[root@localhost ~]# A=10
[root@localhost ~]# B=20
[root@localhost ~]# C=$A
[root@localhost ~]# A=$B
[root@localhost ~]# B=$C
[root@localhost ~]# echo $A
20
[root@localhost ~]# echo $B
10

总结

for

读取不同的变量值,用来逐个执行同一组命令

while

重负测试某个条件,只要条件成立则反复执行

until

重复测试某个条件,只要条件不成立则反复执行