Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does "set -e" work with subshells?

I was wondering whether set -e propagates through subshells (i.e. does a subshell inherit the -e setting of its parent), so I made some experiments. I found some strange results that I can't explain.

First, here are some basic tests. They return what I expect.

( true; false )         # 1
( false; true )         # 0
( set -e; false; true ) # 1

Now I tried what happens if I put a subshell within my subshell. This expression returns 1, which suggests that it propagates.

( set -e; ( false; true ) )

Then I tried these expressions. I expected them to return 1, but I found that they return 0.

( set -e; ( true; false ); true )
( set -e; ( set -e; false; true ); true )

Why? In both cases, the inner subshell returns 1, whether set -e propagates or not (as I checked in the beginning). The outer subshell has set -e, which means that it should fail after the inner subshell exits, but it does not. Can someone explain this?

like image 533
petersohn Avatar asked Mar 25 '14 09:03

petersohn


People also ask

What is set E in shell?

Set –e is used within the Bash to stop execution instantly as a query exits while having a non-zero status. This function is also used when you need to know the error location in the running code.

What does set in shell script do?

The set command is a built-in Linux shell command that displays and sets the names and values of shell and Linux environment variables. On Unix-like operating systems, the set command functions within the Bourne shell ( sh ), C shell ( csh ), and Korn shell ( ksh ).

What does #!/ Bin Bash mean?

#!/bin/bash Essentially it tells your terminal that when you run the script it should use bash to execute it. It can be vital since you may be using a different shell in your machine ( zsh , fish , sh , etc.), but you designed the script to work specifically with bash.

What is set in scripts?

Set command: It is used to set or unset specific flags and settings( determines the behavior of the script and helps in executing the tasks without any issue.) inside the shell environment. It can be used to change or display the shell attributes and parameters.


2 Answers

Prior to bash 4, set -e appears to only cause the shell to exit if a simple command has a non-zero exit (emphasis mine):

-e Exit immediately if a simple command (see SHELL GRAMMAR above) exits with a non-zero status.

In bash 4 (possibly 4.1, I don't have a 4.0 to check), the effect of -e was extended to more complicated commands:

-e Exit immediately if a pipeline (which may consist of a single simple command), a subshell com- mand enclosed in parentheses, or one of the commands executed as part of a command list enclosed by braces (see SHELL GRAMMAR above) exits with a non-zero status.

like image 146
chepner Avatar answered Oct 04 '22 21:10

chepner


From man bash:

set [+abefhkmnptuvxBCEHPT] [+o option-name] [arg ...]

-e

Exit immediately if a pipeline (which may consist of a single simple command), a subshell command enclosed in parentheses, or one of the commands executed as part of a command list enclosed by braces (see SHELL GRAMMAR above) 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 !. A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each subshell environment separately (see COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell.

So when a false is found, it exits from the subshell.

See a couple of examples:

# when `false`, exit. Hence, no `echo ho`
$ ( set -e; echo hi; false; echo ho ) ; echo $?
hi
1

# when `false`, exit. Hence, no `echo hu`
$ ( set -e; echo hi; true; echo ho; false; echo hu ) ; echo $?
hi
ho
1
like image 44
fedorqui 'SO stop harming' Avatar answered Oct 04 '22 21:10

fedorqui 'SO stop harming'