为什么不使用带有 || 的多个命令或&&条件工作?

为什么不使用带有 || 的多个命令或&&条件工作?

这适用于 shell(bash、dash)提示符:

[ -z "" ] && echo A || echo B
A

不过,我正在尝试写一个POSIXshell脚本,它的开头是这样的:

#!/bin/sh

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

readonly raw_input_string=${1}

[ -z "${raw_input_string}" ] && echo "The given argument is empty."; exit 1

我不知道为什么,但我没有收到消息:

给定的参数为空。

如果我这样调用脚本:

./test_empty_argument ""

这是为什么?

答案1

请注意您的线路

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

这与

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."
exit 1

;在大多数情况下,不带引号的可以替换为换行符)

这意味着exit 1无论向脚本传递了多少参数,该语句始终都会执行。这反过来意味着该消息The given argument is empty.永远没有机会被打印。

要使用“短路语法”在测试后执行多个语句,请将语句分组在{ ...; }.另一种方法是使用正确的if语句(恕我直言,它在脚本中看起来更干净):

if [ "$#" -ne 1 ]; then
    echo 'Invalid number of arguments, expected one.' >&2
    exit 1
fi

你的第二次测试也有同样的问题。


关于

[ -z "" ] && echo A || echo B

这适用于给定的示例,但通用

some-test && command1 || command2

不是

if some-test; then
    command1
else
    command2
fi

相反,它更像是

if ! { some-test && command1; }; then
    command2
fi

或者

if some-test && command1; then
    :
else
    command2
fi

也就是说,如果测试或第一个命令失败,则执行第二个命令,这意味着它有可能执行三个全部涉及的言论。

答案2

这:

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

不是:

[ "${#}" -eq 1 ] || { echo "Invalid number of arguments, expected one."; exit 1; }

但相反的是:

{ [ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; } 
exit 1

无论您向脚本传递了多少参数,脚本都会退出。

答案3

使其更具可读性的一种方法是定义一个die函数(à la perl),例如:

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

# then:

[ "$#" -eq 1 ] || die "Expected one argument, got $#"

[ -n "$1" ] || die "Empty argument not supported"

如果需要,您可以添加更多附加功能,例如颜色、前缀、行号...。

答案4

我经常将其视为空字符串的测试:

if [ "x$foo" = "x" ]; then ...

相关内容