以感叹号开头的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失败,它将返回非零状态.!将否定它,因此该行将返回零状态,脚本将正常继续.

Linux相关问答推荐

在shell 中使用排除模式的grep

是否可以在Bash正则表达式中排除?

Linux在所有多行中用新值替换整个列

boost-iostreams 1.59 sparc-solaris 交叉编译失败

Linux TTY 操作顺序

Git在某些文件中添加回车符,尽管autocrlf已关闭

如何在REPL控制台中使用PowerShell将特定的CSV列转换为TitleCase?

如何使用适用于 Linux 的 Dockerized SQL Server 设置 MSDTC

如何比较 2 个文件并将第二个文件的所有行打印到输出文件 awk

如何在 DolphinDB 中递归查找目录中的所有文件?

如何让 Flutter 用鼠标拖动而不是滚轮滚动? (Linux)

从 Ansible 中的 shell 命令输出中提取特定数据

查找在特定日期从特定机器登录的所有用户

在 Linux 中 Select 多个同名的可执行文件

如何在 Linux 上使用 Python 判断进程是否仍在运行?

如何使用文件描述符刷新写入?

如何使用 Linux 命令找到我的 shell 版本?

事件驱动和异步有什么区别?在 epoll 和 AIO 之间?

在linux中根据内容拆分文件

在我的 index.php 中加载 CSS 和 JS 等资源时出现错误 403