How do I make a sourced script auto-return if any command inside it fails?
Suppose I have a script that auto-exits on failure via set -e, e.g.
#!/bin/bash
# foo.env
set -e # auto-exit on any command failure
echo "hi"
grep 123 456 # this command will fail (I don't have a file named "456")
echo "should not reach here"
If I run the command normally, it will auto-exit on the failed grep command:
box1% ./foo.env
hi
grep: 456: No such file or directory
However, if I source the script, it exits my current shell, not just the script being sourced:
box1% ssh box2
box2% source ./foo.env
hi
grep: 456: No such file or directory
Connection to box2 closed.
box1%
If I remove the set -e,
#!/bin/bash
# foo2.env
echo "hi"
grep 123 456 # this command will fail (I don't have a file named "456")
echo "should not reach here"
then it doesn't auto-exit or auto-return the sourced script at all:
box1% ssh box2
box2% source ./foo2.env
hi
grep: 456: No such file or directory
should not reach here
box2%
The only workaround I've found so far is to add a return expression to every line of code in the script, e.g.
box1% cat foo3.env
#!/bin/bash
# foo3.env - works, but is cumbersome
echo "hi" || return
grep 123 456 || return
echo "should not reach here" || return
box1% source foo3.env
hi
grep: 456: No such file or directory
box1%
Is there another way for sourced scripts, similar to how set -e works for non-sourced ones?
1 Answer 1
When you source a script is like if you were writing that file line by line from the keyboard. It means that set -e will regard the current shell and that on error it will exit from the current shell.
That's a workaround. Today I feel me lazy so I thought that computer can write ||return for me, or better to read line by line the file and execute so:
#!/bin/bash
# this is the file MySource.sh
while IFS='' read -r line
do
[[ $line == \#* ]] || $line || return
done < "1ドル"
execute it with . MySource.sh FileToBeSourced.sh
If your FileToBeSourced.sh script is with one line commands it should work.
Far far away to be ready to be used in a production environment.
Test it and eventually use it at your own risk.
It skips lines that start with # because they should cause the error # command not found.
-
That's a clever trick. It turns out my scripts span many lines, so I'd have to make a fancier parser. Maybe the best way is to find a parser or hack one up in Perl and have it stream commands instead of
read.Mr Fooz– Mr Fooz2015年06月09日 18:14:35 +00:00Commented Jun 9, 2015 at 18:14 -
@MrFooz: Thanks, it was just an idea. With a fancy parser you can get rid of the ungraceful
[[ $line == \#* ]] ||too. Maybe you can put the parsed output at the end of the loopdo.. done <<< $( FancyParser.sh "1ドル" )Hastur– Hastur2015年06月10日 08:25:31 +00:00Commented Jun 10, 2015 at 8:25