【Shell】Shell编程中的布尔运算


布尔运算

  • 常规的布尔运算
    • 在shell下如何进行逻辑运算
    • true or false
    • 与运算
    • 或运算
    • 非运算,取反
    • Bash中的true 和 false是我们通常认为的1和0么?
    • 返回值 VS 逻辑值
  • 条件测试
    • 条件测试的基本使用
    • 数值测试
    • 字符串测试‘
    • 文件测试
    • 各种逻辑测试的组合
    • 如果a,b,c都等于下面对应的值,那么打印yes,通过-a进行与测试
    • 测试某个"东西"是文件或者目录,通过-o进行或运算
    • 测试某个"东西"是否为文件,通过!非运算
    • 比较-a与&&,-o与||,!test与test!
    • 要求某个文件可执行且有内容,用-a和&&分别实现
    • 要求某个字符串要么为空,要么与某字符串相等
    • 测试某个数字不满足指定的所有条件
  • 命令列表
    • 命令列表的执行顺序
    • 如果ping通www.xganfeni.top,那么打印连通信息
    • 命令列表的作用
    • 在脚本里判断程序的参数个数
  • 小结

常规布尔运算

这里主要介绍 Bash 里头常规的逻辑运算,与、或、非。

在 Shell 下如何进行逻辑运算

示例:true or false

单独测试 true 和 false ,可以看出 true 是真值, false 为假

$ if true;then echo "YES"; else echo "NO"; fi
YES
$ if false;then echo "YES"; else echo "NO"; fi
NO

示例:与运算

$ if true && true;then echo "YES"; else echo "NO"; fi
YES
$ if true && false;then echo "YES"; else echo "NO"; fi
NO
$ if false && false;then echo "YES"; else echo "NO"; fi
NO
$ if false && true;then echo "YES"; else echo "NO"; fi
NO

示例:或运算

$ if true || true;then echo "YES"; else echo "NO"; fi
YES
$ if true || false;then echo "YES"; else echo "NO"; fi
YES
$ if false || true;then echo "YES"; else echo "NO"; fi
YES
$ if false || false;then echo "YES"; else echo "NO"; fi
NO

示例:非运算

$ if ! false;then echo "YES"; else echo "NO"; fi
YES
$ if ! true;then echo "YES"; else echo "NO"; fi
NO

可以看出truefalse 按照我们对逻辑运算的理解进行着,但是为了能够更好的理解Shell 对逻辑运算的实现,我们还得弄清楚, truefalse 是怎么工作的?

Bash 里头的 true 和 false 是我们通常认为的 1 和 0 么?

回答是:否。

示例:返回值 v.s. 逻辑值

truefalse它们本身并非逻辑值,它们都是 Shell 的内置命令,只是它们的返回值是一个“逻辑值”:

$ true
$ echo $?
0
$false
$ echo $?
1

可以看到 true 返回了 0,而 false则返回了 1 。跟我们离散数学里学的真值 1 和 0 并不是对应的,而且相反的。

范例:查看 true 和 false 帮助和类型

$ help true false
true: true
    Return a successful result.

false: false
    Return an unsuccessful result.
$ type true false
true is a shell builtin
false is a shell builtin

说明: $? 是一个特殊变量,存放有上一次进程的结束状态(退出状态码) 。

条件测试

从上节中,我们已经清楚地了解了 Shell 下的“逻辑值”是什么:是进程退出时的返回值,如果成功返回,则为真,如果不成功返回,则为假。而条件测试正好使用了 test 这么一个指令,它用来进行数值测试(各种数值属性测试) 、字符串测试(各种字符串属性测试) 、文件测试(各种文件属性测试) ,我们通过判断对应的测试是否成功,从而完成各种常规工作,再加上各种测试的逻辑组合后,将可以完成更复杂的工作。

条件测试基本使用

数值测试

$ if test 5 -eq 5;then echo "YES"; else echo "NO"; fi
YES
$ if test 5 -ne 5;then echo "YES"; else echo "NO"; fi
NO

字符串测试

$ if test -n "not empty";then echo "YES"; else echo "NO"; fi
YES
$ if test -z "not empty";then echo "YES"; else echo "NO"; fi
NO
$ if test -z "";then echo "YES"; else echo "NO"; fi
YES
$ if test -n "";then echo "YES"; else echo "NO"; fi
NO

文件测试

$ if test -f /boot/System.map; then echo "YES"; else echo "NO"; fi
YES
$ if test -d /boot/System.map; then echo "YES"; else echo "NO"; fi
NO

各种逻辑测试的组合

如果 a,b,c 都等于下面对应的值,那么打印 YES,通过 -a 进行"与"测试

$ a=5;b=4;c=6;
$ if test $a -eq 5 -a $b -eq 4 -a $c -eq 6; then echo "YES"; else echo "NO"; fi\
YES

测试某个“东西”是文件或者目录,通过 -o 进行“或”运算

$ if test -f /etc/profile -o -d /etc/profile;then echo "YES"; else echo "NO"; fi
YES

测试某个“东西”是否为文件,测试 ! 非运算

$ if test ! -f /etc/profile; then echo "YES"; else echo "NO"; fi

NO

上面仅仅演示了 test 命令一些非常简单的测试,你可以通过 help test 获取 test 的更多用法。需要注意的是, test 命令内部的逻辑运算和 Shell 的逻辑运算符有一些区别,对应的为 -a&&-o|| ,这两者不能混淆使用。而非运算都是 ! ,下面对它们进行比较。

比较 -a 与 &&, -o 与 ||, ! test 与 test !

要求某文件可执行且有内容,用 -a 和 && 分别实现

$ cat > test.sh
#!/bin/bash
echo "test"
[CTRL+D] # 按下组合键CTRL与D结束cat输入,后同,不再注明
$ chmod +x test.sh
$ if test -s test.sh -a -x test.sh; then echo "YES"; else echo "NO"; fi
YES
$ if test -s test.sh && test -x test.sh; then echo "YES"; else echo "NO"; fi
YES

要求某个字符串要么为空,要么和某个字符串相等

$ str1="test"
$ str2="test"
$ if test -z "$str2" -o "$str2" == "$str1"; then echo "YES"; else echo "NO"; fi
YES
$ if test -z "$str2" || test "$str2" == "$str1"; then echo "YES"; else echo "NO"; fi
YES

测试某个数字不满足指定的所有条件

$ i=5$ if test ! $i -lt 5 -a $i -ne 6; then echo "YES"; else echo "NO"; fi
YES
$ if ! test $i -lt 5 -a $i -eq 6; then echo "YES"; else echo "NO"; fi
YES

很容易找出它们的区别,-a-o 作为测试命令的参数用在测试命令的内部,而 &&|| 则用来运算测试的返回值,! 为两者通用。需要关注的是:

- 有时可以不用 ! 运算符,比如eqne刚好相反,可用于测试两个数值是否相等; -z 与 -n 也是对应的,用来测试某个字符串是否为空。

 Bash 里, `test`命令可以用`[]`运算符取代,但是需要注意,`[ 之后与 ]`之前需要加上额外的空格。
  • 在测试字符串时,所有变量建议用双引号包含起来,以防止变量内容为空时出现仅有测试参数,没有测试内容的情况 。

下面我们用实例来演示上面三个注意事项:

  • neeq 对应的,我们有时候可以免去 ! 运算

    ``` $ i=5 $ if test $i -eq 5; then echo "YES"; else echo "NO"; fi YES $ if test $i -ne 5; then echo "YES"; else echo "NO"; fi NO $ if test ! $i -eq 5; then echo "YES"; else echo "NO"; fi NO

    ```

  • [ ]可以取代 test,这样看上去会“美观”很多

    ``` $ if [ $i -eq 5 ]; then echo "YES"; else echo "NO"; fi YES $ if [ $i -gt 4 ] && [ $i -lt 6 ]; then echo "YES"; else echo "NO"; fi YES

    ```

  • 记得给一些字符串变量加上 "" ,记得[ 之后与 ] 之前多加一个空格

    `` $ str="" $ if [ "$str" = "test"]; then echo "YES"; else echo "NO"; fi -bash: [: missing]' NO $ if [ $str = "test" ]; then echo "YES"; else echo "NO"; fi -bash: [: =: unary operator expected NO $ if [ "$str" = "test" ]; then echo "YES"; else echo "NO"; fi NO

    ```

    正是基于逻辑运算特有的性质,我们可以通过 &&||来取代if/then 等条件分支结构,这样就产生了命令列表。

命令列表

命令列表的执行规律

命令列表的执行规律符合逻辑运算的运算规律,用 && 连接起来的命令,如果前者成功返 回,将执行后面的命令,反之不然;用 || 连接起来的命令,如果前者成功返回,将不执行 后续命令,反之不然。

如果 ping 通 www.xganfeni.top,那么打印连通信息

$ ping -c 1 www.xganfeni.top -W 1 && echo "=======connected======="

命令列表的作用

有时用命令列表取代 if/then 等条件分支结构可以省掉一些代码,而且使得程序比较美观、 易读,例如:

在脚本里判断程序的参数个数,和参数类型

#!/bin/bash
echo $#
echo $1
if [ $# -eq 1 ] && (echo $1 | grep '^[0-9]*$' >/dev/null);then
echo "YES"
fi

说明:上例要求参数个数为 1 并且类型为数字 。

再加上 exit 1 ,我们将省掉 if/then 结构

#!/bin/bash
echo $#
echo $1
! ([ $# -eq 1 ] && (echo $1 | grep '^[0-9]*$' >/dev/null)) && exit 1
echo "YES"

这样处理后,对程序参数的判断仅仅需要简单的一行代码,而且变得更美观。

小结

介绍了 Shell 编程中的逻辑运算,条件测试和命令列表。

  • test中判断文件的各种方法
  • 与或非的逻辑使用
  • 多判断语句之间与或非逻辑的方法
  • 比较a/-o&&/||的区别