bash的陷阱(1): 逻辑或碰到local修饰符的情况

bash的函数如果有返回值,并要赋值给一个变量,跟普通的命令调用没有差异,都是: v=$(func) 的方式。需要注意的是,这里执行了fork操作,如果函数里有调用exit的话,只是让子进程退出,当前进程并不会退出。如果想要让当前进程也退出,可以使用set -e或在函数调用结束的时候再判断一次,比如:

v=$(func) || exit $?

如果函数调用失败,当前进程也退出。

今天遇到一个跟这个相关的陷阱,但并不是fork的问题,而是bash语法解析的问题,先看看我当时的写法,脚本简化后:

$ cat a.sh
#!/bin/bash

foo() {
    echo "error" && exit 1
}

bar() {
    local r=$( foo ) || exit $?
    echo $r # 执行了这里
}

bar

如上,函数bar以fork的方式调用foo,我们预期是foo返回值不为0时,bar函数也退出。所以上面bar函数里最后的echo $r不应该被执行到。但实际运行的时候发现这段代码确实可以执行到bar函数的最后一行。

后来,去掉了local修饰符,执行符合预期了:

bar() {
    r=$( foo ) || exit $?
    echo $r # 不会执行到这里
}

看来是 r=$( foo ) || exit $? 里的逻辑或||被解析器作为等号后边两个命令的逻辑运算;而前边加了local修饰符之后,逻辑或||被当成表达式local r=$(foo) 与 命令 exit 之间的逻辑运算。

发表评论

电子邮件地址不会被公开。 必填项已用*标注