Exit statusWhen you type commands, you can usually tell whether they worked or not. Commands that are unable to do what you asked usually print an error message. This is sufficient if you are typing in each command by hand and looking at the output, but sometimes (for example, if you are writing a script) you want to have your commands react differently when a command fails. To facilitate this, when a command finishes it returns an exit status. The exit status is not normally displayed; instead it is placed in a variable (a named memory slot) named "$?". The exit status is a number between 0 and 255 (inclusive); zero means success, and any other value means a failure. One way to see the exit status of a command is to use the echo command to display it:
$ echo "this works fine" this works fine $ echo $? 0 $ hhhhhh bash: hhhhhh: command not found $ echo $? 127 Now we'll look at various ways to handle errors.
if/thenHandling an error is an example of something you do conditionally: if something happens, then you want to take action. The shell provides a compound command--a command that runs other commands--called if. The most basic form is: if <command> then <commands-if-successful> fi We will start with a basic example, then improve it to make it more useful. After we type if and press the Enter key, the shell knows we're in the middle of a compound command, so it displays a different prompt (>) to remind us of that. $ if > man ls > then > echo "You now know more about ls" > fi The manual page for ls scrolls by You now know more about ls Running this command will bring up the manual page for ls. Upon quitting with 'q', the man command will have exited successfully and the echo command will run. Handling command failure
Adding an else clause allows us to specify what to run on failure: if <command> then <commands-if-successful> else <commands-if-failed> fi Let's run apropos if the man command fails. $ if > man draw > then > echo "You now know more about draw" > else > apropos draw > fi ... list of results for apropos draw ... This time the man command failed because there is no draw command, activating the else clause. && and ||The if-then construct is very useful, but rather verbose for chaining together dependent commands. The "&&" (and) and "||" (or) operators provide a more compact format. command1 && command2 [&& command3]... The && operator links two commands together. The second command will run only if the first has an exit status of zero, i.e., if the first command was successful. Multiple instances of the && operator can be used on the same line. $ mkdir mylogs && cd mylogs && touch mail.log && chmod 0660 mail.log Here is an example of multiple commands, each of which assume the prior one has run successfully. If we were to use the if-then construct to do this, we would have ended up with an unwieldy mass of ifs and thens. Note that the && operator short circuits, that is, if one command fails, no subsequent command is run. We take advantage of this property to prevent unwanted effects (like creating mail.log in the wrong directory in the above example). If && is the equivalent of then, the || operator is the equivalent of else. It provides us a mechanism to specify what command to run if the first fails. command1 || command2 || command3 || ... Each command in the chain will be run only if the previous command did not succeed (ie had a nonzero exit status). $ cd Desktop || mkdir Desktop || echo "Desktop directory not found and could not be created" In this example we try to enter the Desktop directory, failing which we create it, failing which we inform the user with an error message. With this knowledge we can make the helpme function we wrote earlier more compact. Our previous examples have shown the two operators used in isolation, but they can be mixed as well. $ function helpme() {
man $1 && echo "you now know more about $1" || apropos $1
}
As you probably suspect, the 'you now know...' echo is not exactly the most useful command. (It might not even be accurate, perhaps the man page introduced so many options and confused the poor user). We heartily confess we threw it in just to match the original if-then syntax. Now that we know about the || operator, we can further simplify the function to: $ function helpme() {
man $1 || apropos $1
}
That covers the concept of exit status and using it to control the flow of your command and scripts. We hope you leave this chapter with an exit status of zero! |