Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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 0 when a file with carriage return is found, and ! negates the value to the return code is then 1 and the script exits. When used with grep (no xargs) this works without parentheses. When xargs is 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?

like image 397
Colton Leekley-Winslow Avatar asked Sep 19 '16 20:09

Colton Leekley-Winslow


People also ask

What are {} used for in Bash?

Bash brace expansion is used to generate stings at the command line or in a shell script. The syntax for brace expansion consists of either a sequence specification or a comma separated list of items inside curly braces "{}". A sequence consists of a starting and ending item separated by two periods "..".

What is the purpose of the double parentheses (( )) in the scripts?

Similar to the let command, the (( ... )) construct permits arithmetic expansion and evaluation. In its simplest form, a=$(( 5 + 3 )) would set a to 5 + 3, or 8.

What are [] in Bash?

[[ … ]] double brackets are an alternate form of conditional expressions in ksh/bash/zsh with a few additional features, for example you can write [[ -L $file && -f $file ]] to test if a file is a symbolic link to a regular file whereas single brackets require [ -L "$file" ] && [ -f "$file" ] .

What does brackets do in Bash?

Parentheses are often used for enclosing conditions and for function parameters. Braces are used for function bodies and objects. And brackets are used for lists or array notation. In Bash, that's often a little different and in many cases, parentheses, braces, and brackets act as commands themselves.


1 Answers

Your problem has nothing to do with xargs.

The -e option of bash is a little tricky.

-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 !.

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.

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

$ 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
$ 
like image 183
Leon Avatar answered Sep 27 '22 21:09

Leon