什么意思! 在shell中的一个命令之前?

问题在于标题。 以惊叹号开头的shell命令(shell脚本的一部分)的目的是什么? 具体例子:

在foo.sh中:

#!/usr/bin/env bash set -e ! docker stop foo ! docker rm -f foo # ... other stuff 

我知道,没有空间的感叹号用于历史replace和! <expression> 根据手册页的 ! <expression>可以用来评估“ 如果expr是假的,则为真 ”。 但是在这个对我来说没有意义的例子中。

TL; DR:这只是绕过你所使用的特定行中的set -e标志。


添加hek2mgl的正确和有用的答案 。

你有:

 set -e ! command 

Bash参考手册→pipe道描述:

pipe道中的每个命令都在其自己的子shell中执行。 pipe道的退出状态是pipe道中最后一个命令(…)的退出状态。 如果保留字“!” 在stream水线之前,退出状态是如上所述的退出状态的逻辑否定 。 在返回值之前,shell等待pipe道中的所有命令终止。

这意味着! 在一个命令之前是否定它的退出状态:

 $ echo 23 23 $ echo $? 0 # But $ ! echo 23 23 $ echo $? 1 

要么:

 $ echo 23 && echo "true" || echo "fail" 23 true $ ! echo 23 && echo "true" || echo "fail" 23 fail 

退出状态在许多方面是有用的。 在您的脚本中,与set -e一起使用,只要命令返回非零状态,脚本就会退出。

因此,当你有:

 set -e command1 command2 

如果command1返回一个非零的状态,脚本将会结束,不会进入command2

不过,也有一个值得一提的问题,在4.3.1 The Set Builtin中描述:

-e

如果可能由单个简单命令(请参阅简单命令),列表(请参阅列表)或复合命令(请参阅复合命令)组成的pipe道(请参阅pipe道)返回非零状态,请立即退出。 如果失败的命令是命令列表的一部分,那么shell将不会立即退出 ,直到关键字,if语句中的testing的一部分,以及在&&或||中执行的任何命令的一部分。 列表,除了最后的&&或||之后的命令,pipe道中的最后一个命令 ,或者命令的返回状态与! 。 如果复合命令以外的子shell返回非零状态,因为命令失败,而-e被忽略,shell不会退出。 如果设置了ERR,则会在shell退出之前执行陷阱。


考虑到所有这些因素,当你有:

 set -e ! command1 command2 

你正在做的是绕过set -e标志在command1 。 为什么?

  • 如果command1正常运行,它将返回一个零状态。 ! 将否定它,但是set -e将不会触发退出,因为它来自于与!相反的返回状态,如上所述。
  • 如果command1失败,它将返回一个非零状态。 ! 将否定它,所以行将最终返回一个零状态,脚本将继续正常。

如果您不希望脚本在这两种情况下失败,错误或成功的命令,您也可以使用此替代方法:

 set -e docker stop foo || true 

布尔值或真值使得stream水线总是有0作为返回值。

“!” 意思是“不”,所以当你把它放在一个命令之前,你运行“$?”。 它会回应一个1.这意味着它失败,而不是0,这意味着成功。