为什么我需要括号在 bash `set -e` 和否定返回码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39581150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 15:12:18  来源:igfitidea点击:

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

linuxbashshellxargs

提问by Colton Leekley-Winslow

I have a shell script which checks for windows line endings.

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

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

I am using the !character to negate the return code of the command. Grep will return code 0when a file with carriage return is found, and !negates the value to the return code is then 1and the script exits. When used with grep(no xargs) this works without parentheses. When xargsis used the negation takes place according to $?, as echo $?will print 1, however the script does not exit! After adding parentheses around the whole command, it works as expected. Why are the parentheses needed?

我正在使用该!字符来否定命令的返回码。0当找到带回车的文件时,Grep 将返回代码,并!否定返回代码的值,然后1脚本退出。当与grep(no xargs)一起使用时,它无需括号即可工作。当xargs使用否定根据发生$?,如echo $?将打印1,但是脚本不会退出!在整个命令周围添加括号后,它按预期工作。为什么需要括号?

回答by Leon

Your problem has nothing to do with xargs.

你的问题与xargs.

The -eoption of bash is a little tricky.

-ebash的选项有点棘手。

-eExit 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 exitif the command that fails is part of the command list immediately following a whileor untilkeyword, part of the test following the ifor elifreserved 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 !.

-e如果管道(可能由单个简单命令组成)、列表复合命令以非零状态退出,则立即退出。 壳不退出如果失败的命令是紧跟在所述命令列表的一部分whileuntil关键字,继该测试的一部分ifelif保留字,在执行任何命令的一部分&&||除命令列表以下的最终&&||,任何命令在管道中但最后一个,或如果命令的返回值与!.

Let's look at a much simpler example:

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

$ 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
$

So, even though the exit status of "! true" was non-zero, the script was allowed to run to the end and output the value of the exit status. That's because we didn't have any failing command - the non-zero exit code was due to deliberate negation.

因此,即使 " ! true"的退出状态不为零,脚本也可以运行到最后并输出退出状态的值。那是因为我们没有任何失败的命令——非零退出代码是由于故意否定。

However, if we enclose "! true" in parentheses we introduce a failing (compound) command.

但是,如果我们将“ ! 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
$ 

回答by Ruslan Osmanov

The set -ecommand instructs to

set -e命令指示

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

如果命令以非零状态退出,则立即退出

(see help set).

(见help set)。

In Bash, an expression in parentheses creates a subshell(subprocess), which works like a single command. Thus, if a subshell exits with an error code, the parent script exits, too (due to the -esetting).

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

So if grepfinds the \rcharacter, the subshell exits with non-zero status; the main script exits with this code, too (due to set -e).

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

The answer to your question Why are the parentheses needed?is: because you probably want to exit the main script, if grepfinds a \rcharacter in one of the files under git control.

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