Wednesday, January 20, 2010

bash error checking

Just had an interesting one bite me.

I like to do a lot of error checking in bash.  There are so many easy ways to destroy a system; something like this:

cd /nonexistentdirectory
rm -f *

can just ruin your whole day.  So I usually do something simple, like:

cd /nonexistentdirectory||exit 1
rm -f *

That works.  But if you've got it in the middle of a script, you'll never know about it.  The obvious thing to do is to mail yourself a message.

cd /nonexistentdirectory||(echo "$0 failed chdir"|mailx tim;exit 1)
This works fine.  That is, it emails me a nice error message - and then proceed to destroy all of my files.  See, it tosses up a subshell - a completely separate instance of bash.  Here's a little experiment.

  TESTVAL="testing"
  echo "testval before=$TESTVAL"

  cd /nonexistentdirectory||(TESTVAL="not a test";echo $TESTVAL)

  echo "testval after=$TESTVAL"

Running it shows:

testval before=testing
/usr/local/scripts/verify_full: line 25: cd: /nonexistentdirectory: No such file or directory
testval=not a test
testval after=testing

 So my variable gets changed to what I want it to - and then as soon as I drop out of that subshell, it changes back.  My 'exit 1' had the no effect at all - it droped me out of the subshell (which I was about to exit anyway) back to the main shell, and then proceeded to destroy all of my files.

Curly braces to the rescue.

cd /nonexistentdirectory||{ TESTVAL="not a test";echo "testval=$TESTVAL"; }

testval before=testing
/usr/local/scripts/verify_full: line 25: cd: /nonexistentdirectory: No such file or directory
testval=not a test
testval after=not a test


Now, the 'exit 1' really will drop you out of the whole script.  Your files are saved!

One gotcha - note the semicolon before the closing brace.  If you forget to put it there, you will search for a long time trying to find out why the script is failing.



No comments:

Post a Comment