shell—流程控制
本文最后更新于 209 天前,如有失效请评论区留言。

Auther | CuckooYang

shell流程控制

条件结构

条件为真返回 0,条件为假返回 1

1.文件测试

2.字符串比较

3.数字比较

文件

-f  # 存在且是正规文件 
-d  # 存在且是目录
-h  # 存在且是符号链接 
-b  # 块设备
-c  # 字符设备
-e  # 文件存在

【案例】:
[root@localhost ~]# vim test.sh
#!/usr/bin/bash
file=/opt/test.txt
touch /opt/test.txt
if [ -e $file ];then
        echo "$file"
else
        echo "文件不存在"
fi

字符串

-n STRING
    the length of STRING is nonzero
    -n    #字符串的长度,不是零成功。
-z STRING
    the length of STRING is zero
     -z   #字符串的长度,是零成功(对于未定义或赋予空值的变量将是为空串)

STRING1 = STRING2   (等于)
           the strings are equal
STRING1 != STRING2  (不等于)
           the strings are not equal

【案例】:
# vim string.sh
#!/usr/bin/bash
while :
do
read -p "请输入你的密码: " a   #可以有多个变量来接受键盘输入的值
pass=123456
if [ -z $a ];then
        echo "您输入的密码不能为空"
        exit 1
else
        if [ $a = $pass ];then
                echo "登录成功"
                break
        else
                echo "您的密码输入有误,请重新输入"
        fi
fi
done

数字

-eq(equal)     #等于
-ne(not equal) #不等于
-ge(Greater than or equal to)  #大于等于 
-le(Less than or equal to)     #小于等于 
-gt(greater than) #大于
-lt(less than)    #小于 

shell语句

if语句

(1)控制流

•在一个shell脚本中的命令执行顺序称作脚本的流。大多数脚本会根据一个或多个条件来改变它们的流。 
•流控制命令:能让脚本的流根据条件而改变的命令称为条件流控制命令 
•exit语句:退出程序的执行,并返回一个返回码,返回码为0正常退出,非0为非正常退出,例如: 
•exit 0

(2)语法

if    #代码返回0表示真,非0为假
if语句语法如下: 
if [ list1 ];then    #list1:你的测试条件,你要测试什么,对什么内容做判断
    list2
elif [ list3 ];then  #接着在怎么做。(多条件判断)
    list4
else                 #如果前面的命令没有执行成功那就执行else下面的命令。
    list5
fi

(3)案例

【案例1】:
[root@linux-server ~]# cd /opt/test/script/
[root@linux-server script]# vim testif.sh
#!/bin/bash
read -p "请输入号码: " num 
if [ $num = 1 ];then
        echo "1"
elif [ $num = 2 ];then
                echo "2"
else 
                echo "输入有误!"
fi
[root@linux-server script]# chmod +x testif.sh

【案例2】:
例:脚本if.sh,必须在脚本后加上适当的参数脚本才能正确执行
[root@linux-server script]# vim if.sh
#!/bin/bash
if [ "$1" = "hello" ]; then
        echo "Hello! How are you ?"
elif [ "$1" = "" ]; then
                echo "You MUST input parameters"
else
                echo "The only accept parameter is hello"
fi
[root@linux-server script]# chmod +x if.sh
测试:
[root@linux-server script]# ./if.sh 
[root@linux-server script]# ./if.sh hello
[root@linux-server script]# ./if.sh 434

【案例3】:
1)检测apache是否运行,如果没有运行则启动,并记录启动的时间,保存到日志中。
2)测试ip地址主机位从2到100的机器是否存活,并把存活的机器记录到文本文件alivehost.txt内。(使用ping命令)
案例
#!/usr/bin/bash
ip=192.168.198
for i in {2..100}
do
        ping -c1 $ip.$i &> /dev/null
                if [ $? -eq 0 ];then
                        echo "$ip.$i is up" >> activehost.txt
                else
                        echo "$ip.$i is down"
                fi
done

(4)多个条件联合

  • 逻辑与

    &&:逻辑与,前面执行成功,后面才执行。前面命令执行失败,后面命令也不执行
    if [ $condition1 ] && [ $condition2 ];then 
    if [[ $condition1 && $condition2 ]];then
  • 逻辑或

    ||:逻辑或,前面执行失败,后面执行,前面命令执行成功,后面不执行。
    if [ $condition1 ] || [ $condition2 ];then 
    if [[ $condition1 || $condition2 ]];then

(5)练习

1. ping主机测试
2. 判断一个用户是否存在
3. 判断当前内核主版本是否为3,且次版本是否大于10
4. 判断vsftpd软件包是否安装,如果没有则自动安装 (yum是否能用,不能用自动修复,安装完成测试以下,是否能用。)
5. 判断httpd是否运行
6. 判断指定的主机是否能ping通,必须使用$1变量
7. 报警脚本,要求如下:
    根分区剩余空间小于20%
    内存已用空间大于80%
    向用户alice发送告警邮件
    配合crond每5分钟检查一次
    echo "邮件正文" | mail -s "邮件主题" alice 可以报警
8. 判断用户输入的是否是数字 
read -p "请输入:" get
case $get in 
[0-9][0-9]*)     #判断输入是否是数字
        echo -e "你输入是数字。\n"
;; 
*)
        echo -e "你输入的不是数字。\n"
;; 
esac

case语句

shell 中流控制的第二种方式。

(1)语法

case $变量 in
     pattern1)
          list1
          ;;        #结尾。
     pattern2)
          list2
          ;;
     ... ...
     patternN)
          listN
         ;;
    *)              #如果前面命令没有执行成功那么执行下面这个
         list*
         ;;
esac

命令;;:表明流应该跳转到case语句的最后,类似C语言中的break指令。
第一行: 声明case关键字调用case语法, 紧跟的“变量”一般为用户的输入值, in代表从下方的各个模式进行匹配 
第2-4行: 匹配到“pattern1”后进行命令的输出或执行, pattern1: 一般为字符或数值
第11-12行: 当用户输入的字符不存在匹配模式时, 直接执行或打印*)下的命令或语句

(2)案例

【案例1】:
[root@linux-server script]# vim foo.sh
#!/usr/bin/env bash
case $1 in
        foo)
        echo "bar"
        ;;
        bar)
        echo "foo"
        ;;
        *)
        echo "Usage:$0 '{foo|bar}'"
        ;;
esac
[root@linux-server script]# chmod +x foo.sh
[root@linux-server script]# ./foo.sh bar

【案例2】:
[root@linux-server script]# vim system_tools.sh
#!/usr/bin/env bash
cat <<-EOF 
+-------------------------------------------------------------------------+ 
|                             System_tools V1.0                           | 
+-------------------------------------------------------------------------+
|                     a. Stop And Disabled Firewalld.                     |
|                     b. Disabled SELinux Secure System.                  |
|                     c. Install Apache Service.                          |
|                     d. Quit                                             | 
+-------------------------------------------------------------------------+ 
EOF
echo "Please input your select: " && read var
case "$var" in
        "a")
        systemctl stop firewalld && systemctl disable firewalld
                ;; 
        "b")
                setenforce 0
                ;; 
        "c")
                yum -y install httpd httpd-tools
                ;; 
        "d")
                exit
                ;; 
          *)
                printf "请按照上方提供的选项输入!!!\n"
                ;; 
esac
[root@linux-server script]# chmod +x system_tools.sh
[root@linux-server script]# ./system_tools.sh

【练习】:
1.建立脚本case.sh,当执行时,要求我们在键盘输入适当的值(one|two|three),当输入正确时并打印,当输入错误 时会提示你,应该输入正确的值。
2.建立脚本service.sh,当执行的时候要求输入(1、2、3、4、5)时安装对应的httpd、vim、wget、更换aliyum等功能,当输入错误 时会提示你,应该输入正确的值。

for循环语句

(1)语法

for i in {取值范围}  #for是关键字 i是变量名 in是关键字
do                  #循环体的开始
                    #循环体
done                #循环体的结束

(2)案例

【案例1】:
[root@linux-server script]# vim for.sh
#!/usr/bin/env bash
#
# Author:
# Date: 2019/**/**
# 打印1-100
for i in {1..100} 
do
    echo $i 
done

【案例2】:
[root@linux-server script]# vim for1.sh
#!/bin/bash
for (( i=1;i <= 5;i++ ))
do
                echo "$i"
done
[root@linux-server script]# chmod +x for1.sh 
[root@linux-server script]# ./for1.sh
#参数解释:
默认值 i=1 
条件  i<=多少?取决于定义,为用户输入的变量,先条件成立在执行命令
增幅  i++  执行一次加一

#i++和++i区别:
i++===先赋值在运算
++i===先运算在赋值
例子:
[root@localhost script]# i=1
[root@localhost script]# h=1
[root@localhost script]# let x=i++
[root@localhost script]# echo $x
1
[root@localhost script]# echo $i
2
[root@localhost script]# let y=++h
[root@localhost script]# echo $y
2
[root@localhost script]# echo $h
2

【案例3】:
[root@linux-server script]# vim ip.sh
#!/usr/bin/env bash
# Author: 
# 测试成产环境的主机存活性,将up的ip保存在一个文件中,将down的ip保存在一个文件中
src_ip="192.168.246"
for i in {2..254}
do
        {
        ping -c1 $src_ip.$i &>/dev/null
        if [ $? -eq 0 ];then
                echo "alive: $src_ip.$i" >> ip_up.txt
                echo "alive: $src_ip.$i"
        else
                echo "down: $src_ip.$i" >> ip_down.txt
                echo "down: $src_ip.$i"
        fi
        } &
done
wait
echo "finish..."
[root@linux-server script]# chmod +x ip.sh 
[root@linux-server script]# ./ip.sh
#参数详解:
wait:等待上面命令后台执行结束后(即上一个的进程终止),在执行下面的echo命令

【案例4】:
[root@linux-server script]# vim user.sh
#!/usr/bin/bash
# for循环批量创建用户 
read -p "请设置用户名/数量/密码: " prefix num pass
cat <<-EOF
用户前缀:$prefix
用户数量:$num
用户密码:$pass
EOF
for i in $(seq 1 $num)
do
user=$prefix$i
id $user &> /dev/null
if [ $? -eq 0 ];then
        echo "$user is already exist!"
        exit 0
else
        useradd $user &> /dev/null
        echo $pass | passwd --stdin $user &>/dev/null
fi
done
echo "starting create users..."

[root@linux-server script]# chmod +x user.sh 
[root@linux-server script]# ./user.sh

#参数详解:
seq 打印序列号,只跟数字
seq 命令用于产生从某个数到另外一个数之间的所有整数。
打印奇数: # seq 1  2  10:表示1到10以内的奇数,2是步长,因为中间隔2.
seq  -w $num  :-w 所有数取最宽的宽度,前面没有的自动补零。
seq命令的原理就不说了,这里说说为什么不能在{ }中使用变量。其实原因写在bash的man手册中:
大意是说,Bash中会最先展开{ }中的内容,这个时候$NUM还不会被具体的值替代,所以是i在循环中读取的是‘{1..$NUM}’的一个完整的字符串,输出时$NUM会被10替代,就有了'{1..10}'这样的结果。

$(seq 1 4):打印1-4的序列号。

while循环语句

(1)语法

while 条件   #while关键字,条件和if的条件一样,为真时一直循环,为假时不循环
do
            #循环体
done
#注意:while循环处理文件里面的行比较擅长,不管有没有空格都是一行。

(2)案例

【案例1】:
# vim c.sh
#!/usr/bin/bash
# 1小于50则一直打印1
i=1
while [ $i -lt 50 ]
do
        echo $i
done

【案例2】:'通过一个文件批量创建用户'
#背景:写一个脚本,满足以下需求及应用,如一个文件的内容如下,根据文件内容实现批量创建用户,第一列为用户名,第二列为密码
[root@localhost script]# vim user_pass.txt #创建用户和密码文件
user1 qfedu123
user2 qfedu456
user3 qfedu567
user4 qfedu789
user5 qfedu012
[root@localhost script]# vim create_user.sh #编写脚本
#!/usr/bin/bash
[ $UID -ne 0 ] && exit 1
while read line    # line为接受参数,会将user_pass.txt的内容逐条读入,每循环一次读入一行
do
        user=`echo $line | awk '{print $1}'`
        pass=`echo $line | awk '{print $2}'`
        id $user &> /dev/null || useradd $user && echo $pass | passwd $user --stdin
done < /opt/test/script/user_pass.txt

[root@localhost script]# chmod +x create_user.sh 
[root@localhost script]# bash create_user.sh

【案例3】:安装服务
[root@linux-server script]# vim while.sh
#!/usr/bin/env bash
#
# Author:
while 1>0
do
cat <<-EOF 
+-------------------------------------------------------------------------+ 
|                            System_tools V1.0                            | 
+-------------------------------------------------------------------------+
|                      a. Stop And Disabled Firewalld.                    |
|                      b. Disabled SELinux Secure System.                 |
|                      c. Install Apache Service.                         |
|                      d. Quit                                            | 
+-------------------------------------------------------------------------+
EOF
echo " Please input your select: " && read var
case "$var" in
                "a")
                    systemctl stop firewalld && systemctl disable firewalld
                            ;; 
                "b")
                sed -ri s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
                            ;; 
                "c")
                yum -y install httpd httpd-tools
                            ;; 
                "d")
                exit
                ;; 
                  *)
                echo "请按照上方提供的选项输入!!!"
                ;; 
esac
if [ $? -eq 0 ];then 
    clear    #清屏操作
else
        echo "Warning: Your program exist ERROR!!!"
        break
fi 
done

[root@linux-server script]# chmod +x while.sh 
[root@linux-server script]# ./while.sh

【案例4】:嵌套循环
[root@localhost script]# vim test4.sh
#!/usr/bin/bash
for i in {1..100}
do
while [ $i -lt 50 ]
do
        echo $i
        #let i++
done
done

[root@localhost script]# chmod +x test4.sh
[root@localhost script]# bash test4.sh

【案例5】:建立批量删除用户脚本
# vim deluser.sh
#!/usr/bin/bash
read -p "请输入用户名: " na
read -p "请输入要删除的个数? " num
echo $num
read -p "确认要删除$na[Y|y]: " x
if [ $x = Y ] || [ $x = y ];then
for i in $(seq 1 $num )
do
echo "$i"
user=$na"$i"
id $user
if [ $? -eq 0 ];then
        userdel -r $user
else
        exit 9
fi
done
fi
chmod +x deluser.sh
./deluser.sh

【练习题】:
1.输入用户输入的参数,直到用户输入 "end" 结束循环
2.给脚本service.sh进行修改,当执行的时候要求输入(1、2、3、4、5)时安装对应的httpd、vim、wget、更换aliyum等功能,当输入错误 时提示应该输入正确的值但是不会退出。

在shell中,let命令用于指定算术运算,即 let、expr。

比如:let  1+2    expr  $a + 2 

until循环语句

(1)语法

until 条件   #当后面的条件表达式为假的时候的才循环,为真的时候就停止了
do
            #循环体
done

(2)案例

[root@linux-server script]# cat until.sh 
#!/bin/bash
x=1
until [ $x -ge 10 ]
do
        echo $x
        x=`expr $x + 1` 
done

x=1
while [ ! $x -ge 10 ]
do
        echo $x
        x=`expr $x + 1`
done

[root@linux-server script]# chmod +x until.sh 
[root@linux-server script]# ./until.sh
#参数解释:
expr命令可以实现数值运算、数值或字符串比较、字符串匹配、字符串提取、字符串长度计算等功能

循环控制命令

shift、continue、break、exit

(1)shift命令

位置参数可以用shift命令左移。比如 shift 3 表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1、$2、$3丢弃,$0不移动。不带参数的shift命令相当于shift 1。对于位置变量或命令行参数,其个数必须是确定的,或者当Shell程序不知道其个数时,可以把所有参数一起赋值给变量 $*。若用户要求 Shell 在不知道位置变量个数的情况下,还能逐个的把参数一一处理,也就是在 $1 后为 $2,在 $2 后面为 $3 等,则需要用shift把所有参数变成$1。

  • 案例

    【案例1】:
    [root@linux-server script]# cat x_shift3.sh 
    #!/bin/bash
    shift
    echo "第一个位置参数: $1"
    
    [root@linux-server script]# bash x_shift3.sh 2 3 
    第一个位置参数: 3    #在运行脚本时左移,即3左移到2的位置
    
    【案例2】:
    [root@linux-server script]# vim x_shift.sh
    #!/bin/bash
    until [ $# -eq 0 ]
    do
    echo "第一个参数为: $1 参数个数为: $#" 
    shift
    done
    
    执行以上程序: 
    [root@linux-server script]# bash x_shift3.sh 1 2 3 4
    结果显示如下:
    第一个参数为: 1 参数个数为: 4 
    第一个参数为: 2 参数个数为: 3 
    第一个参数为: 3 参数个数为: 2 
    第一个参数为: 4 参数个数为: 1
    #当再继续执行脚本时,位置参数将为空,满足util的条件,故停止循环。
    #从上可知 shift 命令每执行一次,变量的个数($#)减一,而变量值提前一位
    
    【练习】:
    用 until 和 shift 命令计算所有命令行参数的和。
    [root@linux-server script]# vim x_shift2.sh
    sum=0
    until [ $# -eq 0 ] 
    do
        sum=expr $sum + $1
        shift 
    done
    echo "sum is: $sum"
    
    执行上述程序: 
    [root@linux-server script]# bash x_shift2.sh 3 5 7
    其显示结果为:
    15

(2)continue命令

在循环中不执行continue下面的代码,转而进入下一轮循环。

  • 案例

    【案例1】:
    [root@localhost script]# vim break.sh
    #!/usr/bin/bash
    for i in {1..4}
    do
    if [ $i -eq 3 ];then
          continue    #当i取3的时候条件成立,此时会执行continue,则跳出当前循环,继续下一轮循环
    else
          echo $i
    fi
    echo "本次输出结束"
    done
    # 以上是循环部分
    echo "脚本结束循环"
    
    执行上述程序:
    [root@linux-server script]# 
    1
    本次输出结束
    2                  #没有输出3,是因为遇到了continue,跳出了i=3那次的循环(即忽略了i=3的情况) 
    本次输出结束
    4
    本次输出结束
    脚本结束循环
    
    【案例2】:
    [root@linux-server script]# vim break1.sh
    #!/bin/bash
    while :  #默认为真
    do
    echo -n "Input a number between 1 to 5: " 
    read aNum
    case $aNum in
          1|2|3|4|5)
          echo "Your number is $aNum!"
          ;;
          *)
          echo "You do not select a number between 1 to 5, game is over!"
          continue 
          ;;
    esac
    done

(3)break命令

结束并退出本次循环。

  • 案例

    【案例1】:
    [root@localhost script]# vim break.sh
    #!/usr/bin/bash
    for i in {1..4}
    do
    if [ $i -eq 3 ];then
          break    #当i取3的时候条件成立,此时会执行break,则跳出所有循环,终止执行后面的所有循环
    else
          echo $i
    fi
    echo "本次输出结束"
    done
    # 以上是循环部分
    echo "脚本结束循环"
    
    执行上述程序:
    [root@linux-server script]# 
    1
    本次输出结束
    2               #没有输出后面的数字,是因为i=3时,执行了break命令,跳出了所有循环。
    本次输出结束
    脚本结束循环
    
    【案例2】:
    [root@linux-server script]# vim break.sh
    #!/bin/bash
    while :
    do
    echo -n "Input a number between 1 to 5: " 
    read aNum
    case $aNum in
          1|2|3|4|5)
          echo "Your number is $aNum!"
          ;;
          *)
          echo "You do not select a number between 1 to 5, game is over!"
          break 
          ;;
    esac
    done

    continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

(4)exit命令

> 退出脚本,常带一个整数给系统,如 exit 0
  • 案例

    【案例1】:
    [root@localhost script]# vim break.sh
    #!/usr/bin/bash
    for i in {1..4}
    do
    if [ $i -eq 3 ];then
          exit 0    #当i取3的时候条件成立,此时会执行exit,则终止循环并退出脚本程序
    else
          echo $i
    fi
    echo "本次输出结束"
    done
    # 以上是循环部分
    echo "脚本结束循环"
    
    执行上述程序:
    [root@linux-server script]# 
    1
    本次输出结束
    2               #没有输出后面的数字,是因为i=3时,终止循环并退出了脚本程序
    本次输出结束
    脚本结束循环
    
    【案例2】:
    [root@linux-server script]# vim case07.sh 
    #!/bin/bash
    while true
    do
    read -p "请输入[1/2]" num1
    case $num1 in
          1)
          echo $num1
          ;;
          2)         #当我输入2时,进入while死循环,继续做选择,选择2时会执行exit,退出脚本程序
          while true 
          do
          read -p "再次输入[1/2]:" num2
          case $num2 in
                  1)
                  echo $num2
                  ;;
                  2)
                  exit
                  ;; 
          esac
          done
          ;;      #注意这里的;;和第一个2)对应
    esac
    done

可理解为:break是立马跳出循环;continue是跳出当前条件循环,继续下一轮条件循环;exit是直接退出整个脚本 。

实战-shell堡垒机

ps:整理自己的思路,完善不足的地方

#!/usr/bin/env bash
#
# Author:
#可以先添加上账密验证环节
while : 
do
trap ':' INT EXIT TSTP TERM HUP  #拒绝ctrl+c以任何方式退出脚本。
clear
cat <<-EOF 
+-------------------------------------+
|        JumpServer @Version1.0       | 
+-------------------------------------+
| a. WebServer Apache.                |
| b. MySQL Databases Server.          |
| c. PHP Development Computer.        |
| d. Quit                             |
+-------------------------------------+
EOF
    read -p "Please input your jump to server's number: "  computer
    case $computer in
    a)
            ssh jumper@192.168.161.129
            ;; 
    b)
            ssh jumper@192.168.161.130
            ;; 
    c)
            ssh jumper@192.168.161.131
            ;; 
    d)
            exit
            ;; 
    *)
        printf "ERROR: Please redo your select!"
            ;; 
    esac
done

---END

版权声明:除特殊说明,博客文章均为cuckooyang原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。 | 博客订阅:RSS | 广告招租:留言板 | 博客VPS |
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇