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:
exit 0
(success).exit 1
(general error such as "divide by zero" and other impermissible operations).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
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.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
exitterminate at least due to the following reasons:exit
builtin command without arguments. Again, the exit status is that of the last command executed.exit
command with an argument. The exit status is the value of the argument.set -u
/set -o nounset
is in effect. The exit status depends on the shell, but is nonzero. (Bash seems to use127
.)(*)set -e
/set -o errexit
is in effect. The exit status is that of the failing command. (But see BashFAQ 105 for issues withset -e
.)1
.)(*)trap
builtin command. This also applies to e.q. hitting Ctrl-C, which sends theSIGINT
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 toset -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
uses1
to indicate no match was found, and values greater than1
to indicate errors. Bash's builtins also use2
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 from0
to255
.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 of128 + <signal number>
, e.g.143
for a child terminated withSIGTERM
.(* Unlike scripts, interactive shells will not exit due to syntax errors or
set -u
orSIGINT
.)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 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 thinkSHLVL
initializes at1
.)