Bash – Conditional execution block with || and parentheses problem

bashshellshell-script

So this should be simple. I am trying to test a condition at the top of a script and bail out of the entire script when the condition fails, and I have two statements I want to execute when I bail. With a lone exit and no second statement, it's fine, but no matter how I add a second statement, I can't get it to completely exit. The implicit cosmetic rule is that this must be all on one line. I discovered this when this one-liner change to a script did not work as intended. The script kept going.

First let me show what does work. The following line completely exits if the $USER variable isn't 'x', and that's good. I know this works because typing this line into a terminal window will close that terminal window (unless your user id really is 'x'), so it's really doing a top-level exit:

[ $USER = 'x' ] || exit 1

So this is good and just as I want, except I want to echo a message before exiting; however, if I try to add the echo, the exit no longer occurs or rather it seems to occur "differently," like perhaps in a bash function context or something. The next line will not close your terminal, and this is bad.

[ $USER = 'x' ] || (echo "Time to bail" ; exit 1)

I thought maybe the semi-colon was getting eaten by echo, but no, the exit does seem to be getting hit. How do I know? I changed the code above and then echoed $? and I saw whatever value I put where you see "1" above. And of course I was viewing these values in a terminal window that I wanted to be closed, and it wasn't closed.

The next variation also shows a second way to perform an echo and a second statement, but again the exact same behavior occurs when an exit is used:

[ $USER = 'x' ] || (echo "Time to bail" && exit 1)

I'm hoping someone here is going to make this all not only not strange but sensible-seeming.

So is this not possible to do on one line?

(bash --version: GNU bash, version 4.3.30(1)-release)

Best Answer

What you're searching is something like this:

[ "$USER" = "x" ] || { echo "Time to bail"; exit 1; }

The { list; } statement executes the commands in the given list in the current shell context. No subshell is created, unlike in the ( list ) notation. An exit call between parentheses will exit that subshell and not the parent shell itself.


The examples in your question with the if-statement on one line or multiple lines are syntactically correct. I cannot reproduce that behavior. It doesn't matter how many lines there arre; the if-statement never starts a subshell in its body.


BTW: I added double quotes to the variable in the condition, because when the variable $USER is empty, the construct would expand to [ = "x" ] which is not valid. With double quotes it expands to [ "" = "x" ].

Related Question