/bin/sh 中逻辑表达式链的评估

evaluation of logical expression chain in /bin/sh

我无法理解此 posix shell 代码的工作原理。

my_dir=/tmp/foo_dir
[ -d $my_dir ] || mkdir -p $my_dir || echo "Error creating '$my_dir'!"

考虑目录不存在的情况。

-d returns 如果目录不存在则为零,因此会评估 "mkdir"。

mkdir returns 成功后为零,这应该导致 "echo" 也被评估。但是此代码有效(echo 仅在通过将 my_dir 更改为 /ttmp/foo_dir" 导致目录创建失败时打印)

在posixshell中,0表示成功,其他值表示失败。当我们在逻辑表达式中使用命令时,我们正在测试它的退出状态。我们可以使用 $? 来检查最后的退出状态。

正在试验:

$ true
$ echo $?
0
$ false
$ echo $?
1
$ [ -d tmpdir ]
$ echo $?
1
$ mkdir tmpdir
$ echo $?
0
$ mkdir tmpdir
mkdir: tmpdir: File exists
$ echo $?
1
$ mkdir -p tmpdir
$ echo $?
0
$ [ -d tmpdir ]
$ echo $?
0

如您所见,-d returns 目录存在时为 0(成功),否则为 1。同样,mkdir returns 成功创建目录时为 0,否则为 1,但 mkdir -p 不认为文件已存在为错误。

问题在于 || 是一个短路运算符。只有需要的才会被执行。因此,例如,在 true || echo Hello 中,echo Hello 永远不会被执行,因为 || 的左侧始终为真。 && 也是一个短路运算符,false && echo Hello 永远不会执行 echo Hello,因为运算符的左侧始终为假。

牢记所有这些,很容易看出它是如何工作的:

  • 如果目录存在,-d returns 0(成功)和其余操作数不需要计算(由于短路行为)
  • 如果目录不存在,则执行-d return 1(失败)和mkdir -p
    • 如果目录创建成功(记住如果目录已经存在mkdir -p不会return报错),mkdir -preturns 0(成功)并且 echo msg 没有被执行(由于短路行为)
    • 如果目录未成功创建,则评估 mkdir -p returns 1(失败)和 echo msg。它的退出状态是整个表达式的"value"。