在 bash 中,有没有一种方法可以制作更短的(if 或)语句?

Tux*_*ife 8 bash

if [ foo = bar -o foo = car -o foo = jar -o foo = foo ]
  then
    echo yes
fi
Run Code Online (Sandbox Code Playgroud)

为了使事情更有条理,我想尝试将其与列表匹配,例如

if [ foo = {bar,car,jar,foo} ] ; then
Run Code Online (Sandbox Code Playgroud)

显然花括号展开法没有用,要不然我就不会在这里了!但我想知道这样的事情是否可能。

Eli*_*gan 15

它看起来像是您代码中的一个错误,但我们可以将其重构得非常小......

如果你真的用 写了你的表达式[ foo = bar -o foo = car -o foo = jar -o foo = foo ],那么它可以被简化为:

echo yes
Run Code Online (Sandbox Code Playgroud)

此测试始终为真,因为foo = foo始终为真,而这又是因为文字字符串foo始终与其自身相同。

尽管您已经澄清此语法并未出现在您真正使用的代码中,但我保留了这个介绍性部分,因为这样做是一个常见的错误,尤其是在新手中。尝试以foo这种方式检查值在任何 Bourne 风格的 shell 中都不起作用——要检查带有 的变量的值[,您必须使用 执行参数扩展$(见下文)。问题的这一特定方面不是特定于 shell 的。例如,这是在 7 个 Bourne-style shell 中的测试

修复原始代码

也许不是你的意思是检查的的foo变量(即,它的内容,而不是它的名字)对那些字符串。在这种情况下,您的原始代码将变成:

echo yes
Run Code Online (Sandbox Code Playgroud)

这可以通过短路&&运算符稍微缩短:

if [ "$foo" = bar -o "$foo" = car -o "$foo" = jar -o "$foo" = foo ]; then
    echo yes
fi
Run Code Online (Sandbox Code Playgroud)

但它仍然比您可能喜欢的更长、更复杂和更重复。所以,继续……

通过模式匹配缩短形式

您可以使用该[[工具的内置正则表达式匹配运算符:

[ "$foo" = bar -o "$foo" = car -o "$foo" = jar -o "$foo" = foo ] && echo yes
Run Code Online (Sandbox Code Playgroud)

虽然使用case可能是最常见的方式,但[[使用的=~是:

  • 与紧凑使用相同的长度case(见下文)
  • 可以说更符合原始代码的逻辑,因为它使用[[,它的工作方式很像测试表达式。

所以你可能更喜欢那个。 这是我可能会使用的方法,在 bash 中执行此操作。

如果你想做类似的事情但匹配 usinggrep而不是[[with =~,这是类似的:

[[ $foo =~ ^(bar|car|jar|foo)$ ]] && echo yes
Run Code Online (Sandbox Code Playgroud)

或这个:

grep -Eq '^(bar|car|jar|foo)$' <<< "$foo" && echo yes
Run Code Online (Sandbox Code Playgroud)

单衬 case

正如Serg 所说,可以使用case代替if和来简化[。这是经典的方式,可能也是最常见的方式。

Serg 的答案中的方法非常有效,但是对于您正在重构的特定代码,我们可以编写更简单的内容,只需使用case. 没有必要在最后进行一场全面的*)比赛。如果字符串与任何模式都不匹配,则控制只会通过 case 构造并且不执行任何命令,这相当于您的if构造没有else.

grep -Fqe{bar,car,jar,foo} <<< "$foo" && echo yes
Run Code Online (Sandbox Code Playgroud)

这使得它足够短和简单,可以很容易地适应——并且是可读的——在一行上(这似乎是你正在寻找的)。此方法也可移植到 bash 以外的 Bourne 风格的 shell。


Ser*_*nyy 10

我建议使用案例结构。就像是:

case $foo in
    foo|car|bar|jar) echo yes ;;
    *) ;;
esac
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以在、、、 或不匹配时在*)和之间添加;;要执行的命令。例如,您可以打印带有或类似内容的消息。$foofoocarbarjarecho 'wrong input'