什么意思! 在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,这意味着成功。