I’m really surprised by this behaviour of set -e (errexit) flag.
I thought it will stop at any “unhandled” line that returns non-zero value
See my simple script and output
#!/usr/bin/bash
set -o errexit #set -e
set -o nounset #set -u
set -o noglob #set -f
set -o pipefail
echo "START"
fun()
{
echo "Starting fun that has wrong command after wrong command"
touch /not-existing-directory/not-existing-file.txt
echo "ERROR: ${?}"
echo "TEST LINE" >>/not-existing-directory/not-existing-file.txt
echo "YET ANOTHER ERROR:${?}"
cat /not-existing-directory/not-existing-file.txt
echo "STILL EXECUTING DESPITE SO MANY ERRORS: ${?}"
echo "WHY THIS AND FOLLOWING LINES ARE PRINTED? WHY ARE WE STILL EXECUTING DESPITE set -e AND SO MANY UNHANDLED NON-ZERO ERROR CODES?"
return 0
}
if fun
then
echo "OK: ${?}"
else
echo "ERROR: ${?}"
fi
echo "END"
Below is output:
START
Starting fun that has wrong command after wrong command
touch: cannot touch '/not-existing-directory/not-existing-file.txt': No such file or directory
ERROR: 1
./test.sh: line 21: /not-existing-directory/not-existing-file.txt: No such file or directory
YET ANOTHER ERROR:1
cat: /not-existing-directory/not-existing-file.txt: No such file or directory
STILL EXECUTING DESPITE SO MANY ERRORS: 1
WHY THIS AND FOLLOWING LINES ARE PRINTED? WHY ARE WE STILL EXECUTING DESPITE set -e AND SO MANY UNHANDLED NON-ZERO ERROR CODES?
OK: 0
END
My versions: Bash 5.1.16 on Ubuntu 22.04
Could you explain this behaviuor to me? I presume it’s not bug
Best regards!
1
The behavior of set -e
is disabled for the duration of any command tested by an if
statement. Since fun
is being tested, its contents will not trigger an automatic exit.
Behaviors like this are why many people recommend handling errors yourself instead of relying on set -e
. Predicting when it will or won’t trigger requires a lot of care and small changes in code (like testing a function that wasn’t written to be tested) can have big impacts on its behavior.