The commentary on set -e behaviour is a somewhat lacking. To begin with, the concept of a failing line is nebulous. Lines don't fail but commands contained with them can. This distinction is important.
Regarding the sample script, the author implies that the goal is to exit if the git command fails, in which case the appropriate solution is this:
git pull origin master || exit
Now, if git returns a non-zero exit status, the script will exit with the very same status. It's far more obvious what will happen from reading the script and there is no having to contend with the numerous side effects of enabling set -e (more on that below).
Next, the use of the && operator is mentioned as a possible solution:
This approach has nothing in common with set -e because a failing command will not cause the script to exit. Further, the exit status of both find and grep will be disregarded, which is probably not what the author is expecting. In Bash, this deficiency can be addressed with set -o pipefail, in which case the pipeline returns the exit status of the rightmost command that failed, or zero if *all* commands succeeded. Still, in this case, a better approach would be to avoid using pipes at all:
For that matter, using find -delete is safer because it will cope with filenames that contain a newline character (as unlikely as that may be).
In summary, I recommend explicitly using the exit builtin if the failure of a given command should cause the script to exit. Not only does set -e result in action at a distance, but it also brings with it a surprising number of pitfalls that are only understood by experienced Bash practitioners. For more information on this topic, refer to http://mywiki.wooledge.org/BashFAQ/105.
Thanks for your insightful response. Much appreciated. Yeah, explicitness is a good thing and peppering your script with `...|| exit` gives it a chance to make some things exit on failure but allow others to fail and that's fine.
Comment
The commentary on set -e behaviour is a somewhat lacking. To begin with, the concept of a failing line is nebulous. Lines don't fail but commands contained with them can. This distinction is important.
Regarding the sample script, the author implies that the goal is to exit if the git command fails, in which case the appropriate solution is this:
git pull origin master || exit
Now, if git returns a non-zero exit status, the script will exit with the very same status. It's far more obvious what will happen from reading the script and there is no having to contend with the numerous side effects of enabling set -e (more on that below).
Next, the use of the && operator is mentioned as a possible solution:
git pull origin master && find . | grep '\.pyc$' | xargs rm && ./restart_server.sh
This approach has nothing in common with set -e because a failing command will not cause the script to exit. Further, the exit status of both find and grep will be disregarded, which is probably not what the author is expecting. In Bash, this deficiency can be addressed with set -o pipefail, in which case the pipeline returns the exit status of the rightmost command that failed, or zero if *all* commands succeeded. Still, in this case, a better approach would be to avoid using pipes at all:
git pull origin master && find . -name '*.pyc' -delete && ./restart_server.sh
For that matter, using find -delete is safer because it will cope with filenames that contain a newline character (as unlikely as that may be).
In summary, I recommend explicitly using the exit builtin if the failure of a given command should cause the script to exit. Not only does set -e result in action at a distance, but it also brings with it a surprising number of pitfalls that are only understood by experienced Bash practitioners. For more information on this topic, refer to http://mywiki.wooledge.org/BashFAQ/105.
Replies
Thanks for your insightful response. Much appreciated.
Yeah, explicitness is a good thing and peppering your script with `...|| exit` gives it a chance to make some things exit on failure but allow others to fail and that's fine.