You are here
Two simple tricks for better shell script error handling
Psssst. Hey you... yeah you. Word on the street is your shell scripts don't do any error handling. They just chug happily along even when everything is broken.
Because a lowly shell shell script doesn't need any error handling right? WRONG!
Here are two simple tricks that are easy to use and will make your scripts much more robust.
-
Turn on -e mode (do you feel lucky - punk?)
In this mode any command your script runs which returns a non-zero exitcode - an error in the world of shell - will cause your script to itself terminate immediately with an error.
You can do that in your shebang line:
#!/bin/sh -e
Or using set:
set -e
Yes, this is what you want. A neat predictable failure is infinitely better than a noisy unreliable failure.
If you REALLY want to ignore an error, be explicit about it:
# I don't care if evil-broken-command fails evil-broken-command || true
Oh and as long as you're messing with shell modes, -e goes well with -x (which I like to think of as shell X-ray).
Like this:
#!/bin/sh -ex
Or like this:
# turn -x on if DEBUG is set to a non-empty string [ -n "$DEBUG" ] && set -x
That way you can actually see what your script was doing right before it failed.
-
Use trap for robust clean-ups
A trap is a snippet of code that the shell executes when it exits or receives a signal. For example, pressing CTRL-C in the terminal where the script is running generates the INT signal. killing the process by default generates a TERM (I.e., terminate) signal.
I find traps most useful for making sure my scripts clean-up after themselves whatever happens (e.g., a non-zero error code in -e mode).
For example:
#!/bin/sh -e TMPFILE=$(tempfile) trap 'echo "removing $TMPFILE"; rm -f $TMPFILE' INT TERM EXIT echo TMPFILE=$TMPFILE echo hello world > $TMPFILE cat $TMPFILE # gives user a chance to press CTRL-C sleep 3 # false always returns an error false echo "NEVER REACHED"
Note that you can only set one trap per signal. If you set a new trap you're implicitly disabling the old one. You can also disable a trap by specifying - as the argument, like this:
trap - INT TERM EXIT
Comments
If you're going to trap signals, make sure you propagate them
If you decide to trap INT or TERM, it would be wise to properly kill your process with INT or TERM:
Not propagating signals in this manner is being a bad Unix citizen. Bash would have re-raised the SIGNAL, so you should too.
This guy has it figured out: http://www.cons.org/cracauer/sigint.html
Good point!
what about exit command
Can't you just use "&& exit 1" in your cleanup instead of an explicit kill? Or is there a reason you should kill the PID instead?
&& exit 1 looping in the trap
Theorically, if you resend a signal it will be trap again and loop. Even if it works, it is not as clean.
The code for propagating the signal isn't complete
You also need to disable the corresponding trap, before raising the signal again. So the code should be something like
Great post!
I think most people are guily of this. I know I have been but I am forcing myself to do it now. I will definitely be using this! Thanks!
Thanks to Guns as well for his comment above. I've got some reading to do.
Very informational. Thanks a lot!
Very informational. Thanks a lot!
There is more than one shell
Updated the shebang line
no, there's not
/bin/sh is The Shell. Programming in anything else is, at best, unreliably portable. and, linuxisms aside, /bin/sh is not necessarily bash. If you think there's something you can do in some other shell that can't be done in /bin/sh, you probably don't know /bin/sh well enough (or have found an interesting edge case).
(now get off my lawn)
I've been using trap in Korn
I've been using trap in Korn shell for years, works fine :-P
-e is not always a good idea
For simple scripts, -e may make life a little simpler, but be careful.
For instance, tar exits with 1 if a file changes during an archive create (-c), and it'll exit with 2 if a more serious error occurs. So, if you use the -e approach, you'll have to do:
Actually, you can omit the
Actually, you can omit the "set +e" and do:
and it'll work just fine.
Excellent tip!
Thanks.
Very Helpful
set -u # "nounset" also useful
-
shell script for CPU alerts
I have wrote the below script but it asking password for each server. what I will do so that it ask passwod one as it is asking more user name
Exception utility
Here is an example using a utility
http://www.perficient.com/Solutions-and-Services/Business-Integration-SOA/Reusable-Utility-Services
Unix Shell Scripting group by
I know this is old but if you still need it.
Simple awk
Hi Saurav ,
Here is a simple awk statement which will print your output as you wanted
Input.txt
1,B.Sc,Calcutta
1,M.Sc,Stanford
2,M.A.,Pune
3,M.Tech,IIT Guwahati
4,B.Tech,Shibpur
4,M.Tech,Jadavpur
5,B.Lib.,Calcutta
6,B.Sc.,Bangalore
awk statement1:
awk -F, '{a[$1]++;rec[$1]=rec[$1]","$2"."$3}END{for (i in a ) print i","a[i],rec[i]}' Input.txt
Output
1,2 ,B.Sc.Calcutta,M.Sc.Stanford
2,1 ,M.A..Pune
3,1 ,M.Tech.IIT Guwahati
4,2 ,B.Tech.Shibpur ,M.Tech.Jadavpur
5,1 ,B.Lib..Calcutta
6,1 ,B.Sc..Bangalore
Cheers ,
Vijay
shell error "Unable to get term attrs"
I have a simple shell script to run a .bin installer. My Shell script works fine if I run it as standalone. but I have to invoke it from ANT. When I invoke it from ANT, I am .bin installer runs fine, but with below message:
[exec] Extracting 0%....................................................................................................100%
[exec] Unable to get term attrs
[exec] Unable to get term attrs
Can anyone give me a hint what "Unable to get term attrs" and how to fix it?
thanks
I've got the same problem.
I've got the same problem. Did you find a solution?
is the trap working for
is the trap working for script exiting on error too, or how can i make shure if the script exits (even for synatx error maybe) that a defined action is done?
how to protect the script execution from signal
Is there a way to protect a executing shell script from INT TERM.
If there are critical jobs on the way. such as backup/restore.
Thanks
Excellent
Thank you so much for sharing your knowledge. It's work for me :)
#!/bin/sh -e is dangerous
Using #!/bin/sh -e is dangerous; what if I use "sh myscript.sh"? Then the -e flag is not set.
This is why using "set -e" is better, this way the flag *always* gets set, no matter how you run the script.
Also look at -u, which causes the shell to exit on undefined variables.
pipefail
when using set -e, dont forget to also set -o pipefail
man bash
pipefail
If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.
Throw an exception if a file is not found in sftp
Hi,
I need to throw an exception from unix shell if during sftp, the file I am searching for is not found in sftp server location.
Thanks.
From Shell if I return false
From Shell if I return false then the app that is reading the output gives the error message as task failed with shell return code 0. Rather than this I need to show File not Found
In shell, return code 0 is true
Shell scripting to trigger mail
Pages
Add new comment