bash 中的“foo && bar || baz”与“if foo; then bar; else baz”的行为不同

bash 中的“foo && bar || baz”与“if foo; then bar; else baz”的行为不同

我想

[ 1 -eq $1 ] && echo "yes" || echo "no"

行为就像

if [ 1 -eq $1 ]; then
    echo "yes"
else
    echo "no"
fi

但是,当我运行这个脚本时(nocmd是一个不存在的命令)

#!/bin/bash

[ 1 -eq $1 ] && nocmd "yes" || echo "no"

我得到参数“1”的奇怪输出:

me@ubuntu:/tmp$ ./ddd.sh 0
no
me@ubuntu:/tmp$ ./ddd.sh 1
./sh.sh: line 3: nocmd: command not found
no

看起来它的作用是这样的:

if [ 1 -eq $1 ]; then
    nocmd "yes"
    if [ $? -ne 0 ]; then
        echo "no"
    fi
else
    echo "no"
fi

还好吗?我错过了什么吗?

答案1

除了整体退出状态外,它的行为如下:

if
  ! { 
    [ 1 -eq $1 ] && nocmd "yes"
  }
then
  echo no
fi

在:

A || B

B当且仅当失败时执行A。这是一个 OR 运算符。

在您的情况下A,iff 成功运行[ 1 -eq $1 ] && nocmd "yes"(AND 运算符),在这种情况下, 的退出状态将是 的退出状态。换句话说,如果或失败,则会执行(请记住,只有成功时才会运行)。nocmd[Anocmdecho no[nocmd "yes"nocmd[

这些x && y || z都是肮脏的黑客行为。正是出于这个原因,最好避免使用它们。如果您确实需要 if/then/else 逻辑,请使用if//构造。仅当您想要时才使用,除非和都成功。thenelsex && y || zzxy

即使在:

cmd && echo OK || echo >&2 KO

在某些病理条件下可能echo OK会失败(例如标准输出进入完整文件系统上的文件),并且echo >&2 KO最终也可能被执行。

$ bash -c 'true && echo OK || echo KO >&2' > /dev/full
bash: line 0: echo: write error: No space left on device
KO

答案2

好吧,实际发生的事情是这样的(这就是如何&&工作||的)

test 1 -eq $1
ret=$?
if [ $ret -eq 0 ]; then
    nocmd "yes"
    ret=$?
fi
if [ $ret -ne 0 ]; then
    echo "no"
fi

在你的情况下,如果$1不等于1或不是有效号码,那么你有一个非零$?,第一个if被跳过,第二个if打印“no”。如果$1equals 1,则nocmd "yes"执行,返回非零$?,并且也会回显“no”。

答案3

您缺少的是对左侧命令的退出状态进行操作 - 左关联性&&。当且仅当该组命令返回非成功退出状态时, ||您有here some group of commands || echo "no", and才会被回显。no

那组命令是什么?在第一种情况下,你有[ 1 -eq "$1" ] && echo "yes".如果[部分失败,则会被视为失败退出状态[ 1 -eq "$1" ] && echo "yes",因此您echo "no"将运行。另外由于左关联性,当“$1”为1时, [ 1 -eq $1 ]返回成功,然后让nocmd运行不存在的shell,shell将返回错误退出状态,整个组将具有失败退出状态,因此回显`“no” 。

相比之下,在你的 if 语句中

if [ 1 -eq $1 ]; then
    echo "yes"
else
    echo "no"
fi

采取哪条路线仅取决于[部分的退出状态。在[ 1 -eq "$1" ] && echo "Yes" || echo "no"echo 中也起着决定是否echo "no"运行的作用。

你的第二个 if 语句示例也不同

if [ 1 -eq $1 ]; then
    nocmd "yes"
    if [ $? -ne 0 ]; then
        echo "no"
    fi
else
    echo "no"
fi

after 并不取决于逻辑运算符链接中发生echo "no"的情况。当然,您在执行完之后仍然执行该部分,但是这里它的退出状态没有与其所属的整个部分分组在一起。elsenocmdecho "no"nocmdif

相关内容