Shell语言用例

bash的if语句用法之:判断外部命令结果

2018-10-14  本文已影响3人  CodingCode

如何在if语句条件表达式里面调用外部命令(函数,或者外部脚本),然后根据外部命令的执行结果确定走什么分支。

基本语法:

if command; then
  do-actions;
fi

含义是命令command如果执行成功,也就是返回值为0,那么执行do-actions,否则就不执行。

反过来场景,如果命令command执行不成功,也就是返回值不为0,那么执行do-actions的格式是:

if ! command; then
  do-actions;
fi

给一个例子:

#!/bin/bash

function foo() {
    if [ "${1}" == "YES" ]; then
        echo "It's YES"
        return 0
    else
        echo "It's not YES"
        return 1
    fi
}

if foo "YES"; then
    echo "Match: YES"
fi

if ! foo "Not YES"; then
    echo "Match: Not YES"
fi

运行结果如下:

It's YES
Match: YES
It's not YES
Match: Not YES

进一步,能不能具体到不同的返回值呢

前面例子中我们只是判断命令是否执行成功,也就是返回时是否为0,那么能不能区分具体的返回值呢,例如当返回值为1时,才执行do-actions,其他返回值2、3、...忽略呢;像:

if command == 1; then
  do-actions
fi

我查了一些资料,遗憾的是没有找到有这样的办法,基本上只能先调用命令,然后判断返回值,像:

command
if [ $? - eq 1 ]; then
  do-actions
fi

或者,

ret=command
if [ ${ret} - eq 1 ]; then
  do-actions1
elif [ ${ret} - eq 2 ]; then
  do-actions
elif [ ${ret} - eq 3 ]; then
  do-actions3
elif ...
  ...
fi

又,能不能使用输出而不是返回值判断呢

当然是可以的,正常使用$(command)得到输出,然后比较就行了。

#!/bin/bash

function foo() {
    if [ "${1}" == "YES" ]; then
        echo "It's YES"
        return 0
    else
        echo "It's not YES"
        return 1
    fi
}

if [ "$(foo 'YES')" == "It's YES" ]; then
    echo "Match: YES"
fi

if [ "$(foo 'NO')" == "It's not YES" ]; then
    echo "Match: NO"
fi

运行结果:

Match: YES
Match: NO

需要注意的是,判断命令输出的例子中,我们把命令的返回值丢弃了,也就是并没有判断命令是否执行成功,只判断了输出是什么。

如果要严格判断,

OUT1="$(foo 'YES')"
if [ $? -eq 0 -a "${OUT1}" == "It's YES" ]; then
    echo "Match: YES"
fi

OUT2="$(foo 'NO')"
if [ $? -eq 0 -a "${OUT2}" == "It's not YES" ]; then
    echo "Match: NO"
fi

这样运行结果:

Match: YES

此时,第二部分判断就不成立,以为$?不为0了。

又,判断多个命令的执行

可以使用&&和||来组合多个命令的执行。

#!/bin/bash

function foo00() { echo foo00; return 0; }
function foo01() { echo foo01; return 0; }

function foo10() { echo foo10; return 1; }
function foo11() { echo foo11; return 1; }


if foo00 "ppp" && foo01 "PPP"; then
    echo "case 1: pass"
else
    echo "case 1: fail"
fi

if foo00 "ppp" && foo10 "PPP"; then
    echo "case 2: pass"
else
    echo "case 2: fail"
fi

if foo10 "ppp" && foo01 "PPP"; then
    echo "case 3: pass"
else
    echo "case 3: fail"
fi

if foo10 "ppp" && foo11 "PPP"; then
    echo "case 4: pass"
else
    echo "case 4: fail"
fi


if foo00 "ppp" || foo01 "PPP"; then
    echo "case 1: pass"
else
    echo "case 1: fail"
fi

if foo00 "ppp" || foo10 "PPP"; then
    echo "case 2: pass"
else
    echo "case 2: fail"
fi

if foo10 "ppp" || foo01 "PPP"; then
    echo "case 3: pass"
else
    echo "case 3: fail"
fi

if foo10 "ppp" || foo11 "PPP"; then
    echo "case 4: pass"
else
    echo "case 4: fail"
fi

执行结果:

foo00
foo01
case 1: pass
foo00
foo10
case 2: fail
foo10
case 3: fail
foo10
case 4: fail
foo00
case 1: pass
foo00
case 2: pass
foo10
foo01
case 3: pass
foo10
foo11
case 4: fail

又,如何用括号分组命令

例如条件A满足,并且条件B或者条件C满足,类似:
A && (B || )

#!/bin/bash

function foo00() { echo foo00; return 0; }
function foo01() { echo foo01; return 0; }

function foo10() { echo foo10; return 1; }
function foo11() { echo foo11; return 1; }

if foo00 && ( foo01 "BB" || foo11 "CC" ); then
    echo "case 1: pass"
else
    echo "case 1: fail"
fi

if foo00 && ( foo10 "BB" || foo11 "CC" ); then
    echo "case 1: pass"
else
    echo "case 1: fail"
fi

运行结果:

foo00
foo01
case 1: pass
foo00
foo10
foo11
case 1: fail

又,普通条件和函数混合使用

$ cat t.sh
#!/bin/bash


function foo0() {
    return 0
}

function foo1() {
    return 1
}

if [ "a" == "a" ] && foo0; then echo "YES1"; fi
if [ "a" == "a" ] && foo1; then echo "YES2"; fi
if [ "a" == "a" ] || foo0; then echo "YES3"; fi
if [ "a" == "a" ] || foo1; then echo "YES4"; fi
if [ "a" == "b" ] && foo0; then echo "YES5"; fi
if [ "a" == "b" ] && foo1; then echo "YES6"; fi
if [ "a" == "b" ] || foo0; then echo "YES7"; fi
if [ "a" == "b" ] || foo1; then echo "YES8"; fi

$ ./t.sh
YES1
YES3
YES4
YES7

这里要注意写法,用&&和||,必须用在[]括号外面,不能放里面:

if [ "a" == "a" && foo ];
if [ "a" == "a" -a foo ];

这两种写法都是错误的。
原因是因为[]和test是等效的,一个[]表达式和一个test是一样的,所有上述写法相当于把foo函数调用写入test语法里面,这是不通的。

比如 [ "a" == "a" -a foo ]等价于 test "a" == "a" -a foo,这个表达式总是返回成功,不管函数foo的返回0还是1。其实在这个情况下,foo并不被认为是一个函数,而是被认为是一个字符串,和"foo"等价:
[ "a" == "a" -a "foo" ]
我们看test的帮助,有这个说明:

$ man test
       -n STRING
              the length of STRING is nonzero

       STRING equivalent to -n STRING

也就是说此时的foo,等价于"foo",等价于 -n "foo",长度是3肯定不等于0,所以表达式总是返回true,而和函数foo没有任何关系了。

小结

  1. if语句调用外部命令时,不要方括号'[]',而直接写命令(包括带参数)即可。
  2. 只能判断命令执行是否成功,返回值0还是非0,不能区分具体的返回值。
  3. 支持多条命令的与或操作, '&& 和 ||'
  4. 支持圆括号'()'对命令进行分组。
上一篇 下一篇

猜你喜欢

热点阅读