条件选择

🔣选择执行 if 语句

  • 单分支

if 判断条件;then
条件为真的分支代码
fi

  • 双分支

if 判断条件; then
条件为真的分支代码1
else
条件为假的分支代码2
fi

  • 双分支

if 判断条件1; then
条件1为真的分支代码1
elif 判断条件2; then
条件2为真的分支代码2

else
以上条件都为假的分支代码N
fi

  1. [root@CentOS /data/script]$ cat if_bmi.sh (#BMI指数测试脚本)
  2. #!/bin/bash
  3. read -p "输入身高(m):" HIGH
  4. if [[ ! "$HIGH" =~ ^[0-2](\.[0-9]{,2})?$ ]];then
  5. echo "身高输入错误!"
  6. exit 1
  7. fi
  8. read -p "输入体重(kg):" WEIGHT
  9. if [[ ! "$WEIGHT" =~ ^[0-9]{1,3}$ ]];then
  10. echo "体重输入错误!"
  11. exit 1
  12. fi
  13. BMI=`echo $WEIGHT/$HIGH^2 |bc`
  14. if [ $BMI -le 18 ];then
  15. echo "太瘦了,多吃点"
  16. elif [ $BMI -le 24 ];then
  17. echo "身材标准,很棒"
  18. else
  19. echo "太胖了,得减肥了"
  20. fi
  21. [root@CentOS /data/script]$ bash if_bmi.sh
  22. 输入身高(m):1.58
  23. 输入体重(kg):59
  24. 身材标准,很棒
  25. [root@CentOS /data/script]$ bash if_bmi.sh
  26. 输入身高(m):333
  27. 身高输入错误!
  28. [root@CentOS /data/script]$ bash if_bmi.sh
  29. 输入身高(m):1
  30. 输入体重(kg):1222
  31. 体重输入错误!
  32. [root@CentOS /data/script]$

🔣条件判断 case 语句

case 变量引用 in
PAT1)
分支1 ;;
PAT2)
分支2;;

*)
默认分支 ;;
esac
case支持glob风格的通配符:* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或者,如: a|b

[root@CentOS /data/script]$ cat lottery.sh        (#抽奖脚本)
#!/bin/bash
read -p "输入数字:" INPUT
case $INPUT in 
1|2|3)
echo "一等奖";;
4|5|6)
echo "二等奖";;
7|8|9)
echo "三等奖";;
*)
echo "谢谢参与";;
esac
[root@CentOS /data/script]$ bash lottery.sh
输入数字:3
一等奖
[root@CentOS /data/script]$ bash lottery.sh
输入数字:12
谢谢参与
[root@CentOS /data/script]$ cat yes-no.sh        (#yes or no 脚本)
#!/bin/bash
read -p "do you agree(yes/no):" INPUT
INPUT=`echo "$INPUT" |tr 'A-Z' 'a-z'`
case $INPUT in
y|yes)
echo "you will agree it";;
n|no)
echo "you will refuse it";;
*)
echo "you input wrong,please iput yes or no";;
esac

[root@CentOS /data/script]$ bash yes-no.sh
do you agree(yes/no):y
you will agree it
[root@CentOS /data/script]$ bash yes-no.sh
do you agree(yes/no):r
you input wrong,please iput yes or no
[root@CentOS /data/script]$ bash yes-no.sh
do you agree(yes/no):n
you will refuse it

练习

1、编写脚本 createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之。并设置初始密码为123456,显示添加的用户的id号等信息,在此新用户第一次登录时,会提示用户立即改密码,如果没有参数,就提示:请输入用户名
2、编写脚本 yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息
3、编写脚本 filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)
4、编写脚本 checkint.sh,判断用户输入的参数是否为正整数
5、编写脚本 reset.sh,实现系统安装后的初始化环境,包括:1、别名 2、环境变量,如PS1等 3、安装常用软件包,如:tree 5、实现固定的IP的设置,6、vim的设置等

循环

将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件
重复运行次数

  • 循环次数事先已知
  • 循环次数事先未知

常见的循环的命令:for, while, until
image.png

🔣for循环

执行机制:依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束
工作中可用for循环批量处理

格式1

  • for NAME [in WORDS … ] ; do COMMANDS; done
  • for 变量名 [ in 列表 ];do

          循环体<br />done
    
  • for 变量名 [ in 列表 ]

do
循环体
done
for循环列表生成方式:

  • 直接给出列表
  • 整数列表:{start..end} $(seq [start [step]] end)
  • 返回列表的命令:$(COMMAND)
  • 使用glob,如:*.sh
  • 变量引用,如:$@,$*,$# ```bash

    范例:面试题,计算1+2+3+…+100的结果

    [root@cent7 /data/script]$ sum=0;for i in {1..100};do let sum+=i;done;echo sum=$sum sum=5050 [root@cent7 /data/script]$ seq -s+ 100 |bc 5050

[root@centos8 ~]#cat /data/scripts/for_sum.sh

!/bin/bash

sum=0 for i in $* ; do let sum+=i done echo sum=$sum [root@centos8 ~]#bash /data/scripts/for_sum.sh 1 2 3 4 5 6 sum=21

九九乘法表

[root@cent7 /data/script]$ 99.sh 11=1
12=2 22=4
13=3 23=6 33=9
1
4=4 24=8 34=12 44=16
1
5=5 25=10 35=15 45=20 55=25
16=6 26=12 36=18 46=24 56=30 66=36
17=7 27=14 37=21 47=28 57=35 67=42 77=49
1
8=8 28=16 38=24 48=32 58=40 68=48 78=56 88=64
1
9=9 29=18 39=27 49=36 59=45 69=54 79=63 89=72 99=81
[root@cent7 /data/script]$ cat 9*9.sh

!/bin/bash

for r in {1..9};do for c in seq "$r";do echo -e “$c$r=$[$r$c]\t\c)” done echo done

```bash
生产案例:将指定目录下的所有文件的后缀改名为 bak 后缀
[root@centos8 ~]#cat /data/scripts/for_rename.sh
#!/bin/bash
DIR=/data/test
cd $DIR
for FILE in * ;do
    PRE=`echo $FILE | sed -nr 's/(.*)\.([^.]+)$/\1/p'`
#   SUFFIX=`echo $FILE | sed -nr 's/(.*)\.([^.]+)$/\2/p'`
    mv $FILE $PRE.bak
done

范例:M37期面试题,要求将目录YYYY-MM-DD/中所有文件,移动到YYYY-MM/DD/下
面试题:扫描一个网段:10.0.0.0/24(10.0.0.1---10.0.0.254),判断此网段中主机在线状态,将在线的主机的IP打印出来
#!/bin/bash
NET=10.0.0
for ID in {1..254};do
   {
    ping -c1 -W1 $NET.$ID &> /dev/null && echo $NET.$ID is up || echo $NET.$ID
is down
   }&
done
wait

格式2

双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格的变量操作I=10;((I++))
image.png image.png

!/bin/bash
for((sum=0,i=1;i<=100;sum+=i,i++));do                       
        true
done
echo $sum

范例:九九乘法表
#!/bin/bash
#语法1实现
for i in {1..9};do
    for j in `seq $i`;do
        echo -e "${j}x$i=$((j*i))\t\c"
    done
    echo
done
#语法2实现
for((i=1;i<10;i++));do
    for((j=1;j<=i;j++));do
        echo -e "${j}x$i=$((j*i))\t\c"
    done
    echo
done
范例:等腰三角形
[root@centos8 scripts]#cat for_triangle.sh
#!/bin/bash
read -p "请输入三角形的行数: " line
for((i=1;i<=line;i++));do
    for((k=0;k<=line-i;k++));do
        echo -e ' \c'
    done
    for((j=1;j<=2*i-1;j++));do
        echo -e '*\c'
    done
    echo
done
[root@cent7 /data/script]$ tang.sh
请输入三角形的行数: 4
    *
   ***
  *****
 *******
范例:生成进度
[root@centos8 ~]#for ((i = 0; i <= 100; ++i)); do printf "\e[4D%3d%%" $i;sleep 0.1s; done

练习

1、判断/var/目录下所有文件的类型
2、添加10个用户user1-user10,密码为8位随机字符
3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,以K开头的输出为文件加stop,以S开头的输出为文件名加start,如K34filename stop S66filename start
4、编写脚本,提示输入正整数n的值,计算1+2+…+n的总和
5、计算100以内所有能被3整除的整数之和
6、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态
7、打印九九乘法表
8、在/testdir目录下创建10个html文件,文件名格式为数字N(从1到10)加随机8个字母,如:1AbCdeFgH.html
9、打印等腰三角形
10、猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,只剩下一个桃子了。求第一天共摘了多少?

🔣while循环

image.pngimage.png

[root@cent7 /data/script]$ cat sum-while.sh 
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ] ;do 
let sum+=$i
let i++
done
echo $sum
  • 无限循环

while true; do
循环体
done

#配置发邮件的邮箱
[root@centos8 ~]#cat .mailrc 
set from=29308620@qq.com
set smtp=smtp.qq.com
set smtp-auth-user=29308620@qq.com
set smtp-auth-password=esvnhbnqocirbicf
set smtp-auth=login
set ssl-verify=ignore
[root@centos8 ~]#cat while_diskcheck.sh
#!/bin/bash
WARNING=80
while :;do    (#冒号表示true,表示无限循环)
   USE=`df | sed -rn '/^\/dev\/sd/s#.* ([0-9]+)%.*#\1#p' |sort -nr|head -n1`
   if [ $USE -gt $WARNING ];then
      echo Disk will be full from `hostname -I` | mail  -s "disk warning" 29308620@qq.com
   fi
   sleep 10
done

练习

1、编写脚本,求100以内所有正奇数之和
2、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态,并统计在线和离线主机各多少
3、编写脚本,打印九九乘法表
4、编写脚本,利用变量RANDOM生成10个随机数字,输出这个10数字,并显示其中的最大值和最小值
5、编写脚本,实现打印国际象棋棋盘
6、后续六个字符串:efbaf275cd、4be9c40b8b、44b2395c46、f8c8873ce0、b902c16c8b、ad865d2f63是通过对随机数变量RANDOM随机执行命令: echo $RANDOM|md5sum|cut -c1-10 后的结果,请破解这些字符串对应的RANDOM值

🔣until循环

image.png

  • until COMMANDS; do COMMANDS; done
  • until CONDITION; do

循环体
done
(进入条件: CONDITION 为false; 退出条件: CONDITION 为true)

  • 无限循环

until false; do
循环体
Done

🔣continue循环

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
while CONDITION1; do
CMD1

if CONDITION2; then
continue
fi
CMDn

done

[root@centos8 script40]#cat continue_for.sh
#!/bin/bash
for ((i=0;i<10;i++));do
 for((j=0;j<10;j++));do
   [ $j -eq 5 ] && continue 2
   echo $j
 done
 echo ---------------------------
done

🔣break循环

break [N]:提前结束第N层整个循环,最内层为第1层
while CONDITION1; do
CMD1

if CONDITION2; then
break
fi
CMDn

done

[root@centos8 script40]#cat break_for.sh
#!/bin/bash
for ((i=0;i<10;i++));do
 for((j=0;j<10;j++));do
   [ $j -eq 5 ] && break 
   echo $j
 done
 echo ---------------------------
done
#********************************************************************
for ((i=0;i<10;i++));do
 for((j=0;j<10;j++));do
   [ $j -eq 5 ] && break 2
   echo $j
 done
 echo ---------------------------
done
[root@centos8 script40]#bash break_for.sh
0
1
2
3
4
[root@centos8 script40]#cat menu.sh
#!/bin/bash
sum=0
COLOR='echo -e \033[1;31m'
COLOR2='echo -e \033[1;32m'
END="\033[0m"
while true;do
 echo -e "\033[33;1m\c"
 cat <<-EOF
1) 鲍鱼
2) 满汉全席
3) 龙虾
4) 燕窝
5) 帝王蟹
6) 退出
 EOF
 echo -e "\033[0m"
 read -p "请点菜(1-6): " MENU
 case $MENU in
 1|4)
   $COLOR'菜价: $10'$END
   let sum+=10
   ;;
 3|5)
   $COLOR'菜价: $20'$END
   let sum+=20
   ;;
 2)
   $COLOR'菜价: $1000'$END
   let sum+=1000
   ;;
 6)
   $COLOR2"你点的菜总价格是:\$$sum"$END
   break
   ;;
 *)
   echo "点错了,没有这道菜"
   ;;
 esac
 $COLOR2"你点的菜总价格是:\$$sum"$END
done
[root@centos8 script40]#cat guess.sh
#!/bin/bash
NUM=$[RANDOM%10]
while read -p "输入 0-9 之间的数字: " INPUT ;do
 if [ $INPUT -eq $NUM ];then
 echo "恭喜你猜对了!"
 break
 elif [ $INPUT -gt $NUM ];then
        echo "数字太大了,重新猜!"
 else
        echo "数字太小了,重新猜!"
    fi
done

🔣shift命令

shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到shift

范例:doit.sh
#!/bin/bash
# Name: doit.sh
# Purpose: shift through command line arguments
# Usage: doit.sh [args]
while [ $You can't use 'macro parameter character #' in math mode# -gt 0 ] # or 
(( $# > 0 ))
do
 echo  $*
 shift
done
./doit.sh a b c d e f g h
范例:示例:shift.sh
#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ] 
do
 echo "$1"
 shift
done
echo   
./shfit.sh a b c d e f g h
[root@centos8 ~]#vim shift_batch_user.sh 
#!/bin/bash
if [ $# -eq 0 ];then
    echo "Usage: ` basename $0` user1 user2 ..."
    exit
fi                                                                                                                                                                
while [ "$1" ];do            (#判断字符串不为空时)
        if id $1 &> /dev/null;then
            echo $1 is exist
        else
           useradd $1
           echo "$1 is created"
        fi
       shift
done
echo "All user is created"
[root@centos8 script40]#bash shift_batch_user.sh tom alice jack
tom is exist
alice is exist
jack is created
All user is created

练习

1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker登录,则将登录时间和主机记录于日志/var/log/login.log中,并退出脚本
2、随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出
3、用文件名做为参数,统计所有参数文件的总行数
4、用二个以上的数字为参数,显示其中的最大值和最小值

🔣while read特殊用法

while 循环的特殊用法,遍历文件或文本的每一行
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
说明:依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

[root@centos8 ~]#echo magedu | read X ; echo $X
[root@centos8 ~]#echo magedu | while read X ; do echo $X;done
magedu
[root@centos8 ~]#echo magedu | { read X ; echo $X; }
magedu
[root@centos8 ~]#echo magedu | ( read X ; echo $X )
magedu
[root@centos8 ~]#echo mage wang zhang | ( read X Y Z; echo $X $Y $Z )
mage wang zhang
[root@centos8 ~]#echo mage wang zhang | while read X Y Z; do echo $X $Y $Z;done
mage wang zhang
cat while_read_diskcheck.sh
#!/bin/bash
WARNING=80
MAIL=root@wangxiaochun.com
df |sed -nr  "/^\/dev\/sd/s#^([^ ]+) .* ([0-9]+)%.*#\1 \2#p"|while read DEVICE 
USE;do
 if [ $USE -gt $WARNING ] ;then
    echo "$DEVICE will be full,use:$USE" | mail -s "DISK WARNING" $MAIL
 fi
done
#********************************************************************
cat while_read_check_dos.sh
#!/bin/bash
lastb | sed -rn '/ssh:/s@.* ([0-9.]{1,3}{3}[0-9]{1,3}) .*@\1@p'|sort |uniq -c
|while read count ip ;do 
 if [ $count -gt 3 ];then
 iptables -A INPUT -s $ip -j REJECT
 fi
done
范例:查看/sbin/nologin的shell类型的用户名和UID
cat while_read_passwd.sh
#!/bin/bash
while read line ;do
        if [[ "$line" =~ /sbin/nologin$ ]] ;then
                echo $line | cut -d: -f1,3
        fi                                                                       

done < /etc/passwd

范例:单词文件
[root@centos6 ~]#wc -l /usr/share/dict/linux.words
479829 /usr/share/dict/linux.words

🔣select循环与菜单

  • select NAME [in WORDS … ;] do COMMANDS; done
  • select variable in list ;do

循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准错误上,并显示 PS3 提示符,等待用户输入;
用户输入菜单列表中的某个数字,执行相应的命令;
用户输入被保存在内置变量 REPLY 中;
select 是个无限循环,因此要用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环;
select 经常和 case 联合使用;
与 for 循环类似,可以省略 in list,此时使用位置参量

cat select.sh 
#!/bin/bash
sum=0
PS3="请点菜(1-6): "
select MENU in 北京烤鸭 佛跳墙 小龙虾 羊蝎子 火锅 点菜结束;do
case $REPLY in
1)
 echo $MENU 价格是 100
 let sum+=100
 ;;
2)
 echo $MENU 价格是 88
 let sum+=88
 ;;
3)
 echo $MENU价格是 66
 let sum+=66
 ;;
4)
 echo $MENU 价格是 166
 let sum+=166
 ;;
5)
 echo $MENU 价格是 200
 let sum+=200
 ;;
6)
 echo "点菜结束,退出"
 break
 ;;
*)
 echo "点菜错误,重新选择"
 ;;
esac
done
echo "总价格是: $sum"