以感叹号开头的shell命令(shell脚本的一部分)的用途是什么?
具体例子:
In foo.sh:
#!/usr/bin/env bash
set -e
! docker stop foo
! docker rm -f foo
# ... other stuff
我知道,如果没有空格,感叹号将用于历史替换,man page中的! <expression>
可用于计算"True if expr is false".但在这个例子中,这对我来说毫无意义.
以感叹号开头的shell命令(shell脚本的一部分)的用途是什么?
具体例子:
In foo.sh:
#!/usr/bin/env bash
set -e
! docker stop foo
! docker rm -f foo
# ... other stuff
我知道,如果没有空格,感叹号将用于历史替换,man page中的! <expression>
可用于计算"True if expr is false".但在这个例子中,这对我来说毫无意义.
TL;DR:这只是通过在使用它的特定行中传递set -e
标志.
加上hek2mgl's correct and useful answer.
你有:
set -e
! command
Bash Reference Manual → Pipelines描述:
管道中的每个命令都在自己的子shell中执行.管道的退出状态是管道中最后一个命令的退出状态(…).If the reserved word ‘!’ precedes the pipeline, the exit status is the logical negation of the exit status如上所述.shell在返回值之前等待管道中的所有命令终止.
这意味着命令前面的!
将否定其退出状态:
$ 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
如果管道(请参见管道)可能由单个简单命令(请参见简单命令)、列表(请参见列表)或复合命令(请参见复合命令)组成,并返回非零状态,请立即退出.The shell does not exit如果失败的命令是紧跟在while或until关键字之后的命令列表的一部分,则是if语句中测试的一部分,是&&;或| |除最后&&;或| |,管道中除最后一个以外的任何命令,或if the command’s return status is being inverted with !.如果子shell以外的复合命令由于在忽略-e时命令失败而返回非零状态,则shell不会退出.如果设置了ERR,则在shell退出之前执行trap on ERR.
考虑到所有这些因素,当你:
set -e
! command1
command2
你要做的是绕过command1
中的set -e
旗.为什么?
command1
正常运行,它将返回零状态.!
将否定它,但set -e
不会触发退出,因为它来自一个与!,如上所述.command1
失败,它将返回非零状态.!
将否定它,因此该行将返回零状态,脚本将正常继续.