为什么我需要括号 In bash `set -e` 和否定 return 代码

Why do I need parenthesis In bash `set -e` and negated return code

我有一个 shell 脚本来检查 windows 行结尾。

set -e
(! git ls-files | xargs grep -I $'\r')

我正在使用 ! 字符来否定命令的 return 代码。 Grep 将 return 代码 0 当找到带有回车符 return 的文件时,并且 ! 否定 return 代码的值然后 1并且脚本退出。当与 grep 一起使用时(没有 xargs),这可以在没有括号的情况下工作。当使用 xargs 时,根据 $? 进行否定,因为 echo $? 将打印 1,但脚本不会退出!在整个命令周围添加括号后,它按预期工作。为什么需要括号?

set -e命令指示

Exit immediately if a command exits with a non-zero status

(参见 help set)。

在 Bash 中,括号中的表达式创建一个 subshell(子进程),其工作方式类似于单个命令。因此,如果子 shell 以错误代码退出,则父脚本也会退出(由于 -e 设置)。

因此,如果 grep 找到 \r 字符,子 shell 将以非零状态退出;主脚本也使用此代码退出(由于 set -e)。

你的问题为什么需要括号?的答案是:因为你可能想退出主脚本,如果grep找到一个\r 字符在 git 控制下的其中一个文件中。

您的问题与xargs无关。

bash的-e选项有点棘手。

-e Exit immediately if a pipeline (which may consist of a single simple command), a list, or a compound command , exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !.

让我们看一个更简单的例子:

$ cat exit_on_error_test.sh 
#!/bin/bash

trap 'echo Interrupted because of an error' ERR
set -e

! true
echo Exit status: $?

$ ./exit_on_error_test.sh 
Exit status: 1
$

因此,即使“! true”的退出状态为非零,脚本也被允许运行结束并输出退出状态的值。那是因为我们没有任何失败的命令 - 非零退出代码是由于故意否定。

但是,如果我们将“! true”括在括号中,则会引入失败的(复合)命令。

$ cat exit_on_error_test.sh 
#!/bin/bash

trap 'echo Interrupted because of an error' ERR
set -e

(! true) # This as a whole is now a failing (compound) command
echo Exit status: $?

$ ./exit_on_error_test.sh 
Interrupted because of an error
$