October 21, 2014
 
 
RSSRSS feed

Linux Commands: Making Bash Error Messages Friendlier

Trapping and Befriending Error Messages

  • March 31, 2010
  • By Akkana Peck

The command line! The bane of the novice Linux user! It's so useful -- yet it can be challenging to learn.

The error messages don't help much. "Command not found." "Permission denied." As a newbie, you need to know more. Isn't that the right command? Why was permission denied? How are you to figure out what the real problem was? And why can't the shell help you with that?

Ubuntu has taken some steps in that direction already. They've set up the bash shell so that if you get "Command not found", most of the time you'll also see suggestions on what you might have meant: commands that are spelled similarly, or commands that aren't installed along with which package you need to install to get them. It looks like this:

$ catt /etc/fstab
No command 'catt' found, did you mean:
 Command 'cat' from package 'coreutils' (main)
 Command 'cant' from package 'swap-cwm' (universe)
catt: command not found

It's an excellent step. Perhaps still not 100% clear -- you still need to know what those packages are and how to install them -- but it's a good start!

But what about other errors, like the all too common "Permission denied"? Ubuntu's error handling uses a function built into bash for that specific purpose, a function called command_not_found_handle that can't be used for other types of errors.

Happily, bash has a more general error trapping mechanism that you can use to handle any kind of error the user might make.

The key is bash's trap command. First you define an error handler function:

function err_handle {
  echo "Place your error handling code here"
}

Then use trap to tell the shell to call your error handler any time it gets an error:

trap 'err_handle' ERR

In the error handler, you can check the shell variable $? to find out what the error code was. So the first step is to figure out which errors you need to catch.

How do you do that? The easiest way is to write a very simple error handler that just prints the numeric code.

function err_handle {
  status=$?
  echo status was $status
}
trap 'err_handle' ERR

Then try typing some commands you know are wrong. For instance, you might misspell the command name:

$ catt foo.html
catt: command not found
status was 127

Or suppose you type the name of an existing file instead of a command:

$ /etc/passwd
bash: /etc/passwd: Permission denied
status was 126

Clearly 126 and 127 are two cases worth handling. There's one other case that's easy for anybody, not just beginners, to hit: a typo in a filename.

$ ls bogusfile
/bin/ls: cannot access bogusfile: No such file or directory
status was 2

So let's catch error 2 as well as 126 and 127. If you have other errors you or people you know tend to hit frequently, you can find out their error codes the same way.

Now you can check in your error handler to make sure you're only handling the types of errors you're prepared to catch:

function err_handle {
  status=$?
  echo status was $status

  if [[ $status -ne 2 && $status -ne 126 && $status -ne 127 ]]; then
    return
  fi

The next problem is to get the exact line the user typed. You'd think that would be easy, but it's the hardest part of the whole endeavor: bash doesn't give you a good way to do it. Here's the best I've found, with help from a number of bash hackers:

  # Get the last typed command.
  lastcmd=$(history | tail -1 | sed 's/^ *[0-9]* *//')

Then split the line into the command (the first word) and arguments (everything else). You can use bash's read command for that:

  read cmd args <<< "$lastcmd"

Now you know the error code and the command. The rest is just a matter of figuring out what sorts of errors your users are likely to hit, then offering them useful suggestions in each case

Sitemap | Contact Us