shell脚本编程笔记(三)—— 流程控制之分支结构

16 篇文章 2 订阅

命令流程通常有三种 —— 顺序、分支及循环,顺序没啥好说的,流程控制的重点在于分支和循环结构。

在了解这两个结构之前,补充一个知识点 —— 退出状态码

一、 退出状态码

1. 含义及查看方法

shell中运行的每个命令其实都有退出状态码,退出状态码是0~255之间的整数值,在命令结束时传给shell,标志命令是否正常执行。0表示正常,其余数字表示各种各样的异常,常见如下:

状态码

描述

0

命令成功结束

1

一般性未知错误

2

不适合的shell命令

126

命令不可执行

127

没找到命令

128

无效的退出

128+x

与Linux信号x相关的严重错误

130

通过ctrl+c终止的命令

255

正常范围之外的退出状态码

 

 

 

 

 

 

 

 

 

 

Linux提供了一个专门的变量$?保存最近一个已执行命令的退出状态码

echo $?

2. 设置方法

默认情况下,shell脚本会以最后一个命令的退出状态码退出,也可以使用exit命令自己设置。设置范围应该在0~255之间,如果大于255,返回的数值会是 设置值%256得到的结果。

可以稍微改下前面的脚本

#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(echo "scale=4; $var1*$var2+$var3*$var4" | bc)
echo The final answer is $var5
exit 5

还可以使用变量作为exit的参数

#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(echo "scale=4; $var1*$var2+$var3*$var4" | bc)
echo The final answer is $var5
exit $var4

下面正式来看分支结构

 

二、 if命令

1. 格式与简单用法

if分支的结构如下所示

#格式1
if commands
then
    commands
elif commands
then
    commands
else
    commands
fi

#格式2,then与if在同一行,注意有分号
if commands;then
    commands
elif commands;then
    commands
else
    commands
fi

与一般编程语言使用表达式判断不同,shell的if可以使用命令,原理就是使用前面的退出状态码,如果状态码为0则执行then后面的语句。例如

#!/bin/bash

myuser=oracle
if grep $myuser /etc/passwd
then
    echo "The user $myuser exists on the system"
else
    echo "The user $myuser doesn't exist on the system"
fi

这种直接在if中判断命令的其实用的也不多,注意还是使用表达式判断,常见有以下三种:

  • 数值判断
  • 字符串判断
  • 文件判断

2. 数值判断

写法较多,每种也有各自优缺点:

  • 方法一: if [ $A -lt $B ]; then ...

    -eq(等于)、-ne(不等于)、lt(小于)、gt(大于)、le(小于等于)、ge(大于等于);缺点:只能比较整数,使用lt,gt等不直观

  • 方法二: if ((A < B)) then ...

优点:简单易理解,允许使用高级数学表达式(例如++、--、位运算、与或非等);缺点:还是只能比较整数

  • 方法三: if (echo $A $B | awk '!($1>$2){exit 1}') then ...

使用awk比较,优点:可以比较小数;缺点:表达式复杂,难记

  • 方法四: if (echo $A - $B | bc -q | grep -q "^-"); then ...

使用bc比较,优点:可以比较小数;缺点:表达式更复杂,难记

以下例子判断指定变量是否为偶数

#!/bin/bash

INT=-5
if [[ ${INT} =~ ^-?[0-9]+$ ]];then #为整数
    if [ ${INT} -eq 0 ];then
        echo "the INT is zero."
    else
        if [ ${INT} -lt 0 ];then
            echo "the INT is negative."
        else 
            echo "the INT is positive."
        fi
        if [ $((INT % 2)) -eq 0 ];then
            echo "the INT is even."
        else
            echo "the INT is odd."
        fi
    fi
else
    echo "the INT is not an integer."
    exit 1
fi

也可以用上面的方法二

#!/bin/bash

INT=-5
if [[ ${INT} =~ ^-?[0-9]+$ ]];then
    if ((INT == 0));then
        echo "INT is zero"
    else
        if ((INT < 0));then
            echo "INT is negative"
        else
            echo "INT is postive"
        fi
        if (( ((INT % 2)) == 0));then
            echo "INT is even"
        else
            echo "INT is odd"
        fi
    fi
else
    echo "INT is not aninteger"
    exit 1
fi

 

3. 字符串判断

  • =或==:等于,if [ "$a" = "$b" ] 或 if [ "$a" == "$b" ]
注意==在[[]]和[]中的行为是不同的,[[]]提供模式匹配功能
1. [[ $a == z* ]] # 如果$a以"z"开头(模式匹配)那么将为true
2. [[ $a == "z*" ]] # 如果$a等于z*(字符匹配)那么结果为true
3. [ $a == z* ] # 将会发生File globbing 和word splitting
4. [ "$a" == "z*" ] # 如果$a等于z*(字符匹配)那么结果为true
  • != 不等于,if [ "$a" != "$b" ], 这个操作符将在[[]]结构中使用模式匹配.
  • < 小于,根据ASCII字母顺序比较大小,if [[ "$a" < "$b" ]] 或 if [ "$a" \< "$b" ] (在[]结构中"<"需要被转义)
  • > 大于,根据ASCII字母顺序比较大小,if [[ "$a" > "$b" ]] 或 if [ "$a" \> "$b" ] (在[]结构中"<"需要被转义)
  • -z 字符串为空或长度为0
  • -n 字符串不为空、长度不为0
#!/bin.bash

# test string : evaluate the value  of a string
ANSWER="maybe"
if [ -z ${ANSWER} ];then
    echo "there is no answer." >&2
    exit 1
fi
if [ ${ANSWER} == "yes" ];then
    echo "the answer is yes."
elif [ ${ANSWER} == "no" ];then
    echo "the answer is no."
elif [ ${ANSWER} == "maybe" ];then
    echo "the answer is maybe."
else
    echo "the answer is unknown."
fi

 

4. 文件判断

  • -e 判断对象是否存在
  • -d 判断对象是否存在,并且为目录
  • -f 判断对象是否存在,并且为常规文件
  • -L 判断对象是否存在,并且为符号链接
  • -h 判断对象是否存在,并且为软链接
  • -s 判断对象是否存在,并且长度不为0(即文件是否不为空)
  • -r 判断对象是否存在,并且可读
  • -w 判断对象是否存在,并且可写
  • -x 判断对象是否存在,并且可执行
  • -O 判断对象是否存在,并且属于当前用户
  • -G 判断对象是否存在,并且属于当前用户组
  • -nt 判断file1是否比file2新  [ "/data/file1" -nt "/data/file2" ]
  • -ot 判断file1是否比file2旧  [ "/data/file1" -ot "/data/file2" ]
#!/bin/bash
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ];then //-e判断是否存在这个文件
    if [ -f "$FILE" ];then
        echo "$FILE is a regular file"
    fi
    
    if [ -d "$FILE" ];then
        echo "$FILE is a directory"
    fi
    
    if [ -r "$FILE" ];then
        echo "$FILE is readable"
    fi
    
    if [ -w "$FILE" ];then
        echo "$FILE is writable"
    fi
    
    if [ -x "$FILE" ];then
        echo "$FILE is executable"
    fi
    
else
    echo "$FILE does not exist"
    exit 1
fi  
exit  

着重说一下最后的exit,exit后面不带参数,默认退出状态为0,如果这个命令出现在脚本的最后一行,默认退出状态以0终止,但是上面这个脚本如果判断出文件不存在,直接就以1退出了,不会运行最后一行的exit
如果我们把上面的shell脚本里的内容变成一个函数,同时要求当目标文件不存在的时候返回状态值1

test_file () {
if ...
...
...
else
    echo "$FILE does not exist"
    return 1
fi
}

 

5. 复合条件判断

即与、或、非

判断符号含义举例
-a 或 &&逻辑与,前面的表达式为真才会执行后面的代码[ 1 -eq 1 -a 1 -ne 0 ] 或者 [ 1 -eq 1 ] && [ 1 -ne 0 ]
-o 或 ||逻辑或,前面的表达式为假才会执行后面的代码[ 1 -eq 1 -o 1 -ne 0 ] 或者 [ 1 -eq 1 ] || [ 1 -ne 0 ]
!逻辑非,对表达式取反if [ ! 表达式 ]

 

 

 

 

 

例1:

#!/bin/bash

MIN_VAL=1
MAX_VAL=100
INT=50
if [[ ${INT} =~ ^-?[0-9]+$ ]];then
    if [[ INT -ge MIN_VAL && INT -LE MAX_VAL ]];then
        echo "$INT is within $MIN_VAL to $MAX_VAL"
    else
        echo "$INT is out of range"
    fi
else
    echo "INT is not an integer" >&2
    exit 1
fi

例2

#!/bin/bash
# test-integer3: determine if an integer is within a
# specified range of values.
MIN_VAL=1
MAX_VAL=100
INT=50
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [ ! \( $INT -gt ${MIN_VAL} -a $INT -lt ${MAX_VAL} \) ]; then
        echo "$INT is not  within $MIN_VAL to $MAX_VAL."
    else
        echo "$INT is out of range."
    fi
else
    echo "INT is not an integer." >&2
    exit 1
fi

 

三、 case命令

多分支判断时简化if语句,判断类型同上。语法格式如下:

#可以使用或 |,这对于处理大小写字符特别方便,模式的书写类似于q|Q)
case variables in 
variables 1 | variables 2)
	command 1;;
variables 3)
	command 2;;
variables 4)
	command 3;;
*)
	default command;;
esac

使用案例

#!/bin/bash

clear
echo "
please select:
1. display disk space
2. display system information
3. display home space utilization
0. quit
"
read -p "enter selection [0-3] >"
case $REPLY in  # REPLY是提供给read命令的默认变量
0) echo "program terminated.";;
1) df -h;;
2) echo "HOSTNAME:$HOSTNAME";;
3) if [ $(id -u) -eq 0 ];then
       du -sh /home/*
   else
       du -sh $HOME
   fi;;
*) 
echo "invalid entry."
   exit 1;;
esac

 

参考

https://www.cnblogs.com/fanyunpeng/p/6412532.html

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hehuyi_In

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值