Shell Scripting – Exit Modes in Shell-Scripting and Bash

bashexitexit-statusfunctionshell-script

I know that in shell-scripting an "exit" usually means voluntarily or at least successfully terminating a session (or a process within a session) and that there are several different exit modes; the following are these I know:

1. A simple exit command

If I'm in the first shell-session (shell-session 0) it will usually cause the shell CLI window to close, but if I'm in some sub-session (like shell-session 1 or later) execution will usually just move my user back to the previous session (say 1 → 0).

2. An exit SOME_EXIT-CODE command

I find three main exit codes used in such exiting:

  1. exit 0 (success).
  2. exit 1 (general error such as "divide by zero" and other impermissible operations).
  3. exit 2 (as in Bash 4.x.x – misuse of shell builtins, and an example would be an empty function; myFunc() {}).

I often find these added to the end of command sequences as indicators of their execution's outcome; sometimes as part of unit testing, as in:

domain="$1" && test -z "$domain" && exit 2 
# Test if a user passes only one domain as a parameter, when executing this script

3. A non-added script exit

If I'm not wrong, when a Bash script ends to run, its "ending" is actually an "exiting" in the common *nix terminology – the script itself is a session from which the user exits back to the CLI sesssion. Here also, some exit code, might be given.

My question

Are there any other "exit modes" in shell scripting in general, and in Bash in particular?

Best Answer

an "exit" usually means voluntarily or at least successfully terminating

At least the POSIX text seems to use exit solely for voluntary termination of a process, as opposed to being killed for an outside reason. (See e.g. wait()) A process being killed by a signal hardly counts as a success, so any successful termination must in that sense be an "exit". Though I'd expect those terms to be used less strictly in informal use.

Are there any other "exit modes" in shell scripting in general, and in Bash in particular?

Mode has particular technical meanings in some contexts (e.g. chmod()), but I can't think of one here, so I'm not exactly sure what it is you're asking.

In any case, a shell script might exit terminate at least due to the following reasons:

  1. The script runs to end of the script. The exit status of the script is that of the last command executed.
  2. The script runs the exit builtin command without arguments. Again, the exit status is that of the last command executed.
  3. The script runs the exit command with an argument. The exit status is the value of the argument.
  4. The script references an unset variable while set -u/set -o nounset is in effect. The exit status depends on the shell, but is nonzero. (Bash seems to use 127.)(*)
  5. The script runs a command that fails while set -e/set -o errexit is in effect. The exit status is that of the failing command. (But see BashFAQ 105 for issues with set -e.)
  6. The script runs into a syntax error. The exit status of the shell is nonzero. (Bash seems to use 1.)(*)
  7. The script receives a signal that causes it to terminate. Not all signals cause termination, and signals can be either ignored or a handler can be set within the script with the trap builtin command. This also applies to e.q. hitting Ctrl-C, which sends the SIGINT signal.(*)

In the technical sense, in cases 1 to 6, the shell process running the script exits voluntarily (i.e. the process calls exit()). On the other hand, from the point of view of the script itself, terminating due to set -e, set -u or a syntax error might well be called involuntary. But the shell script is not the same as the shell interpreter.

In 1 to 3, the custom is to use an exit status of zero for a successful completion, and a non-zero value for failures. The exact meaning of the non-zero values depends on the utility. Some might use only zero and one, some might use different non-zero statuses for different situations. For example, grep uses 1 to indicate no match was found, and values greater than 1 to indicate errors. Bash's builtins also use 2 to indicate errors like invalid options. Using a similar custom may be useful, but you'll need to document what the exit status of your script means. Note that the exit status is usually limited to 8 bits, so the range is from 0 to 255.

In 4 to 6, the situation is usually considered some sort of a failure, so the exit status is non-zero. In 7, there is no exit status. Instead, when a process terminates due to a signal, the wait() system call indicates the signal in question. If the parent process is a shell, it usually represents this with an exit status of 128 + <signal number>, e.g. 143 for a child terminated with SIGTERM.

(* Unlike scripts, interactive shells will not exit due to syntax errors or set -u or SIGINT.)

If I'm in the first shell-session it will usually cause the shell CLI window to close

A terminal emulator will usually close if the process it started exits. But that's up to the terminal emulator, not a function of the shell. A terminal emulator might decide to keep the window open to tell the user that their program terminated, and you could run something other than a shell within a terminal emulator, too.

if I'm in some sub-session,execution will usually just move my user back to the previous session.

If you use an interactive shell to start another shell, the parent shell continues when the child terminates. But again, this isn't related to shells, the same happens if you start an editor or just run any command from an interactive shell. When the child process terminates, the parent shell continues accepting commands from the user.

Bash does keep a variable SHLVL that is increased by one each time Bash starts, so in a sense it does have an internal idea of nested shells. But I don't think the phrase "sub-session" is very common, let alone any sort of numbering of such. (I think SHLVL initializes at 1.)

Related Question