编写bash脚本时与&&等效吗?


31

如果这是一个重复的问题,我提前致歉。在问这里之前,我确实做了搜索/检查的工作。

我很喜欢这样写单行代码:

foocommand && foocommand2 && foocommand3

我的想法是,我只希望在前一个命令“成功”的情况下运行后续命令。

我正在编写一个冗长的脚本,这种单行代码是不可行的,因为它看起来给其他所有人带来了很多混乱的代码。

我想间隔命令并在脚本中在命令之间写注释。我该怎么做却仍然有&&等价的东西?


4
这需要重复:&&并不意味着如果前一个命令成功,则后续命令将运行。这意味着如果命令列表中所有先前命令的累加结果为成功,则该命令将运行。您可能知道这一点,但将来的读者可能会误解。
kojiro

1
同样要注意的是,您所描述的这种行为来自||&&(与|或相反&)称为短路。后一种运算符使用的行为称为“渴望评估”。
AndyPerfect

7
@kojiro:我看不出区别。a && b && c只运行b,如果a成功,所以“只运行c,如果b和”它只能运行成功,“ c如果ab:两个成功”是等效的语句b不能成功,除非a成功。
ruakh

1
@ruakh a || b && c更具说明性。
kojiro

8
@ruakh不,true || false && echo hi将输出hi规范读取为, 运算符“ &&”和“ ||” 应当具有相同的优先级,并应以左联想性进行评估。
kojiro

Answers:


23

您可以这样做:

#!/bin/sh
ls -lh &&
    # This is a comment
    echo 'Wicked, it works!'

希望我能正确理解您的要求。


谢谢。这是我最想做的事。而且,如果需要,它可以很容易地转换回一根衬管。
Mike B

迈克,因为您担心代码的清洁度,所以通常的惯例是在第一个代码的下面缩进该链的2-N部分。
jblaine

@jblaine我不确定我是否理解您的意思。你能详细说明一下吗?
Mike B

迈克,Stackexchange无法让我正确设置答案的格式,所以这就是我的意思:缩进
jblaine

@jblaine好点,已编辑以缩进线条。
Volker Siegel 2014年

38

您可以将shebang行更改为

#!/bin/bash -e

发生任何错误后,脚本将停止。


1
有趣。我会记住这一点。谢谢。
Mike B

使我免于在需要时输入set -e
Silverrocker

@Silverrocker也是POSIX(bash当然部分除外)。POSIX shell带有许多适用于的选项set。或相反亦然?set是在脚本中设置Shell命令行选项的一种方法。
卡兹(Kaz)

7
不幸的是,有许多标准实用程序不遵循通常的退出状态约定,因此-e行为不当。例如,您可能不希望您的脚本在每次diff两个不相同的文件时都终止。当然,您可以通过在此类命令后附加|| true(或也许是|| [ $? = 1 ])来解决此问题,但是OP提到必须阅读此脚本的“其他所有人”,并且说“其他所有人”可能不会习惯于应付-e
ruakh

4
我以前经常把它-e放开,直到我公司的一位管理员一直用来启动我的脚本bash myscript.sh,所以它忽略了-e。现在我所有的脚本set -e在第二行都有一个。
卡洛斯·坎德罗斯(CarlosCampderrós),

19

如果您不喜欢这个set -e主意,也许您可​​以颠倒逻辑。

foocommand || exit 1
foocommand2 || exit 2
foocommand3 || exit 3

更有exit用的是,替换为某些内容以显示有用的错误消息,然后退出。当然,在函数内部,您需要return而不是exit


11
foocommand || exit以退出foocommand状态(如果非零)退出。
斯特凡Chazelas

这是如何运作的?就像在C中一样-如果left参数的计算结果为TRUE,则不检查更多的参数?
沃拉克2013年

是的,这是正确的。这是Lisp(我想应该是功能性语言)和Perl中的常见习语。
2013年

9

您可以if else fi改为使用块。

if foocommand; then

  # some comments

  if foocommand2; then

    # more comments

    foocommand3
  fi
fi

它更具可读性。

或者,您也可以使用\将1号大班轮分成几行

foocommand && \
  # some comment
  foocommand2 && \
    # more comment
    foocommand3

但这当然会使未经训练的眼睛感到困惑。


4
我认为这里\没有必要。
塞缪尔·埃德温·沃德

你是对的。习惯的力量。
马丁·卡纳瓦尔

5

您可以考虑使用嵌套if语句。另一种选择是使用卷曲的分组{ true && echo hi; } || echo huh

更新1:

这是一个没有换行符/注释的示例:

{ { false && echo "inner true"; } && { echo "inner true" && true; } || { echo "inner false" && false; } || echo "outter false"; }

@Stephane感谢您添加分号。我一直在用手机答复,所以我没有仔细检查过我的答案。:)
livingstaccato

有趣的主意。是的,我曾经想到过嵌套if语句,但是如果我将很多东西链接在一起,可能会变得混乱。
Mike B

4

将每个命令序列拆分为功能:

big_block_1() {
  # ...
}
big_block_2() {
  # ...
}
big_block_3() {
  # ...
}

big_block_1 && big_block_2 && big_block_3

0

我总是喜欢编写一个“失败”功能,该功能可以让我指定发生失败时要执行的操作,然后使用该||模式。如下所示:

function fail() {
  echo "Failure: ${@}"
  exit 1
}

foocommand || fail "couldn't foo"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.