Shell 学习(8)Bash 的条件判断

if 结构

语法:

if condition
then
    command
    command
    ...
    
elif condition
then
    command
    command
    ...
    
else
    command
    command
    ...

if then 同写一行时,需要用 ; 分隔

if condition; then
    command
    command
    ...

elif condition; then
    command
    command
    ...
    
else
    command
    command
    ...

也可以只写在一行:

if true; then echo "true"; fi

if true; then echo "true"; else echo "false"; fi
if condition; then fi

true、false、:命令

Bash 中有两个有意思的变量:true、false。这两个命令很简单,就是设置退出码。

# 查看类型
$ type -a true false
true is a shell builtin
true is /usr/bin/true
false is a shell builtin
false is /usr/bin/false

# 测试退出码
$ true
$ echo $?
0

$ false
$ echo $?
1

还有一个更有意思的命令:,没错就是一个冒号,它的效果等价于 true 命令:

# 查看类型
$ type -a :
: is a shell builtin

# 测试退出码
$ :
$ echo $?
0

判断条件

在一般的编程语言中,条件判断通常是判断一个布尔值(true/false),或者 01 这样的数据。但是在 Shell 中,判断的数据有所不同:

1、命令的退出码(执行结果):执行command;后,判断echo $?输出的退出码值(0:true1:false)。

先执行一遍命令后在判断:

$ if echo "before check"; then echo "true"; fi
before check
true

2、算术运算结果(执行结果):执行(( ... ))算术运算扩展后,判断echo $?输出的退出码值(0:true1:false)。

# 不输出
$ if ((0)); then echo "true"; fi
$ if ((2-2)); then echo "true"; fi
# 输出
$ if ((1)); then echo "true"; fi
true
$ if ((1+2)); then echo "true"; fi
true
$ if ((1-2)); then echo "true"; fi
true

注意最后一个测试用例:((1-2)),也进行了打印。这是因为 Bash 的算术运算扩展中,只要计算结果不为0,退出码就返回0。也就是说,只有计算结果为0的时候,退出码才会返回1。
在总结一下:if 判断中的算术运算扩展的计算结果不为0时才会执行 if 下的代码,即使计算结果为负数。

$ ((1-2))
$ echo $?
0

$ ((1-1))
$ echo $?
1

再看一下进行数值比较时的退出码:

$ ((1>1))
$ echo $?
1

$ ((1>0))
$ echo $?
0

这个就很好理解了,如果逻辑正确则返回0(true),否则返回1(false)。

Shell 的条件判断值还可以写多个,但真正判断时,只取最后一个:

# 因为取 false 命令的退出码,所以最后不会输出"true"
if true;false; then
    echo "true";
fi

test 命令

Shell 内置命令,用来检测某个条件是否成立,成立返回0,否则返回1。通常和 if 语句一起使用,并且大部分 if 语句都依赖 test。
test 更常用于BASH shell 脚本中,作为控制逻辑和程序流程 的条件语句的一部分。

# 写法一
test expression

# 写法二
[ expression ]

# 写法三
[[ expression ]]

上面的三种写法等价,但是第三种可以支持正则。并且第二种和三种写法,[]与内部的表达式之间必须有空格,否则无法执行:

# -e 参数:判断文件是否存在
$ test -e /etc/profile
$ echo $?
0

$ [ -e /etc/profile2 ]
$  echo $?
1

$ [ -e /etc/profile]
-bash: [: missing `]'

结合if,汇总一下写法:

# 写法一
if test -e /etc/profile ; then
  echo "Found profile file"
fi

# 写法二
if [ -e /etc/profile ] ; then
  echo "Found profile file"
fi

# 写法三
if [[ -e /etc/profile ]] ; then
  echo "Found profile file"
fi

test 命令详解

文件判断
  1. [ -a file ]:如果 file 存在,则为true。
  2. [ -b file ]:如果 file 存在并且是一个块(设备)文件,则为true。
  3. [ -c file ]:如果 file 存在并且是一个字符(设备)文件,则为true。
  4. [ -d file ]:如果 file 存在并且是一个目录,则为true。
  5. [ -e file ]:如果 file 存在,则为true。
  6. [ -f file ]:如果 file 存在并且是一个普通文件,则为true。
  7. [ -g file ]:如果 file 存在并且设置了组 ID,则为true。
  8. [ -G file ]:如果 file 存在并且属于有效的组 ID,则为true。
  9. [ -h file ]:如果 file 存在并且是一个符号链接,则为true(同 L)。
  10. [ -k file ]:如果 file 存在并且设置了它的“sticky bit”,则为true。
  11. [ -L file ]:如果 file 存在并且是一个符号链接,则为true(同 h)。
  12. [ -N file ]:如果 file 存在并且自上次读取后已被修改,则为true。
  13. [ -O file ]:如果 file 存在并且属于当前用户,则为true。
  14. [ -p file ]:如果 file 存在并且是一个命名管道,则为true。
  15. [ -r file ]:如果 file 存在并且可读(当前用户有可读权限),则为true。
  16. [ -s file ]:如果 file 存在且其长度大于零,则为true。
  17. [ -S file ]:如果 file 存在且是一个网络 socket,则为true。
  18. [ -t fd ]:如果 fd 是一个文件描述符,并且重定向到终端,则为true。 这可以用来判断是否重定向了标准输入/输出/错误。
  19. [ -u file ]:如果 file 存在并且设置了 setuid 位,则为true。
  20. [ -w file ]:如果 file 存在并且可写(当前用户拥有可写权限),则为true。
  21. [ -x file ]:如果 file 存在并且可执行(当前用户拥有执行/搜索权限),则为true。
  22. [ file1 -nt file2 ]:如果 FILE1 比 FILE2 的更新时间最近,或者 FILE1 存在而 FILE2 不存在,则为true。
  23. [ file1 -ot file2 ]:如果 FILE1 比 FILE2 的更新时间更旧,或者 FILE2 存在而 FILE1 不存在,则为true。
  24. [ file1 -ef file2 ]:如果 FILE1 和 FILE2 引用相同的设备和 inode 编号,则为true。

栗子:

#!/bin/bash

FILE=~/.bashrc

if [ -e "$FILE" ]; then
  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/searchable."
  fi
else
  echo "$FILE does not exist"
  exit 1
fi
字符串判断
  • [ string ]:如果string不为空(长度大于0),则判断为真。
  • [ -n string ]:如果字符串string的长度大于零,则判断为真。
  • [ -z string ]:如果字符串string的长度为零,则判断为真。
  • [ string1 = string2 ]:如果string1和string2相同,则判断为真。
  • [ string1 == string2 ]: 等同于[ string1 = string2 ]
  • [ string1 != string2 ]:如果string1和string2不相同,则判断为真。
  • [ string1 '>' string2 ]:如果按照字典顺序string1排列在string2之后,则判断为真。
  • [ string1 '<' string2 ]:如果按照字典顺序string1排列在string2之前,则判断为真。

注意,test命令内部的>和<,必须用引号引起来(或者是用反斜杠转义)。否则,它们会被 shell 解释为重定向操作符。

栗子:

#!/bin/bash

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
整数判断
  • [ integer1 -eq integer2 ]:如果integer1等于integer2,则为true。
  • [ integer1 -ne integer2 ]:如果integer1不等于integer2,则为true。
  • [ integer1 -le integer2 ]:如果integer1小于或等于integer2,则为true。
  • [ integer1 -lt integer2 ]:如果integer1小于integer2,则为true。
  • [ integer1 -ge integer2 ]:如果integer1大于或等于integer2,则为true。
  • [ integer1 -gt integer2 ]:如果integer1大于integer2,则为true。

栗子:

#!/bin/bash

INT=-5

if [ -z "$INT" ]; then
  echo "INT is empty." >&2
  exit 1
fi
if [ $INT -eq 0 ]; then
  echo "INT is zero."
else
  if [ $INT -lt 0 ]; then
    echo "INT is negative."
  else
    echo "INT is positive."
  fi
  if [ $((INT % 2)) -eq 0 ]; then
    echo "INT is even."
  else
    echo "INT is odd."
  fi
fi
正则判断

语法:[[ string1 =~ regex ]]

=~ 是正则比较运算符,后面跟着正则表达式 regex

栗子:

#!/bin/bash

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
  echo "INT is an integer."
  exit 0
else
  echo "INT is not an integer." >&2
  exit 1
fi
test 判断的逻辑运算
  • AND(逻辑与):&&
  • OR(逻辑或):||
  • NOT(非):!

栗子:

#!/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."
  exit 1
fi
普通命令的逻辑运算

如果if不使用test命令,而是普通命令(实际test也是一种命令),可以根据命令的退出码进行逻辑运算。

  • AND(逻辑与):&&
  • OR(逻辑或):||

栗子:

#!/bin/bash

DICTIONARY=/home/shellTest
FIND_FILE=${DICTIONARY}/if.sh

# 判断目录下的指定文件是否为普通文件
if [ -e "${DICTIONARY}" ] && find "${FIND_FILE}" && [ -f "${FIND_FILE}" ]; then
    echo "Found regular file if.sh"
else
    echo "Cannot find regular file if.sh"
fi
if 小结

无论是 test 命令、普通命令、算术运算扩展,if 语句实际只会看它们的退出码。退出码是共性的,所以又可以根据此混合执行、进行逻辑运算执行。

case 结构

switch case结构,用于多值判断。跟包含多个 elif 的 if 结构等价。

语法:

case expression in
  case_pattern1 )
    commands ;;
  case_pattern2 )
    commands ;;
  ...
esac

expression是一个表达式,case_pattern是表达式的值或者一个模式,可以有多个case_pattern,用来匹配多个值,每个case_pattern以两个分号;表示结尾。

例子:

#!/bin/bash

OS=$(uname -s)

case "$OS" in
  FreeBSD) echo "This is FreeBSD" ;;
  Darwin) echo "This is Mac OSX" ;;
  AIX) echo "This is AIX" ;;
  Minix) echo "This is Minix" ;;
  Linux) echo "This is Linux" ;;
  *) echo "Failed to identify this OS" ;;
esac

case 的匹配模式可以使用各种通配符:

#!/bin/bash

echo -n "输入一个字母或数字 > "
# read 命令会在后面的 Blog 中介绍
# 理解为读取用户输入数据即可
read character
case $character in
  [[:lower:]] | [[:upper:]] ) echo "输入了字母 $character"
                              ;;
  [0-9] )                     echo "输入了数字 $character"
                              ;;
  * )                         echo "输入不符合要求"
esac

如果想要当匹配一个值或模式后,继续匹配其他的值或者模式,可以修改表示 case 处理结束的 ;;;;&。例子:

#!/bin/bash

OS=$(uname -s)

case "$OS" in
  Linux) echo "This is Linux" ;;&
  *) echo "Failed to identify this OS" ;;&
esac

执行后输出:

This is Linux
Failed to identify this OS

但是若匹配成功的一个值或模式,以 ;; 结尾,就会直接结束匹配,即使其他的 case 以 ;;& 结尾。

  • 12
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值