Question

I run a command, then an OR so the code block will be executed if the command fails:

#!/bin/sh
test || (
 echo "Test failed, exit!"
 exit 1
)
echo "Test succeeded!"

This works but the script just continues and doesn't exit, Test succeeded is still printed.

I tried using exec:

test || exec <<EOS
  echo "Test failed, exit!"
EOS

But that doesn't run the heredoc at all nor stop the rest of the script...

I am very new to shell scripts.

Was it helpful?

Solution

This is because (..) starts a subshell. Anything process related you do inside it will only affect that subshell.

Instead, use {..} grouping:

#!/bin/sh
test || {
 echo "Test failed, exit!"
 exit 1
}
echo "Test succeeded!"

The (..) behavior is very useful when you actually do want to contain effects, such as

for dir in */
do 
  ( cd "$dir" && make )  # This 'cd' will be contained inside the ()
done

which prevents you from having to keep track of whether you were able to cd in, and therefore whether or not you have to cd .. to make it back to where you were.

OTHER TIPS

@thatOtherGuy has given you the correct answer.

I would encourage you, as a matter of style, if the { grouped block; } is longer than one line, use if:

if test; then
    echo "test succeeded"
else
    echo "test failed, exit" >&2
    exit 1
fi

versus, IMO, the less readable.

test || {
    echo "test failed, exit" >&2
    exit 1
}
echo "test succeeded"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top