exit#
Terminate the program with a status value.
exit evaluates EXPR, runs end-of-program cleanup (END blocks and
object destructors), and then exits the process with that value as
its status code. With no argument it exits 0 — success.
Synopsis#
exit EXPR
exit
What you get back#
Nothing. exit does not return to its caller. It is a statement in
the control-flow sense even though the grammar lets you write it
inside an expression. Code after exit in the same block is
unreachable:
exit 1;
print "never\n"; # dead code
Status values and the 8-bit truncation#
The operating system stores an exit status in 8 bits. Whatever
integer you pass to exit is taken modulo 256 by the kernel before
the parent process sees it. exit 256 looks like exit 0 to the
shell. exit -1 becomes 255. Pass only values in 0..255 and
you avoid the surprise.
The only universally portable values are 0 for success and 1 for
a generic error. Other numbers have conventions — the sysexits.h
range 64..78 on Unix, specific codes expected by sendmail
filters, and so on — but those are agreements between your program
and a specific caller, not guarantees of the language. Exiting 69
(EX_UNAVAILABLE) tells a sendmail incoming-mail filter to defer
the message; the same 69 from a script run by cron means
nothing in particular.
exit 0; # success
exit 1; # generic failure
exit 2; # conventional "misuse" (grep, diff)
exit 77; # conventional "skip" (Automake test)
Cleanup: END blocks and destructors#
exit is not an immediate syscall. Before the process goes
away, Perl:
Runs every
ENDblock in reverse order of compilation (LIFO).Calls
DESTROYon any object whose refcount drops to zero as global destruction tears down pads, the symbol table, and package globals.
Both kinds of cleanup can observe and change $?. The value you
passed to exit is placed in $? on entry to the END/DESTROY
phase; whatever $? holds when the last cleanup returns is the
status the process exits with.
END { $? = 0 if $? == 2; } # rewrite "misuse" to success
exit 2; # process actually exits 0
This is occasionally useful and regularly astonishing. If a module
you did not write installs an END block that touches $?, your
carefully chosen status code can arrive at the parent shell altered.
When you need a hard, unconditional exit that bypasses END and
DESTROY entirely, call POSIX::_exit:
use POSIX ();
POSIX::_exit(3); # no END, no DESTROY, status = 3
Reach for _exit in child processes after fork where the parent
owns the cleanup, and in signal handlers where running arbitrary
Perl code is unsafe.
exit is not die#
exit is the wrong tool for reporting an error from a library or a
subroutine. A caller higher up the stack may want to catch the
failure, log it, and continue — an eval block or a Try::Tiny
wrapper cannot recover from exit. The process is gone.
sub load_config {
my ($path) = @_;
open my $fh, "<", $path
or die "open $path: $!"; # correct — trappable
...
}
# NOT:
# open my $fh, "<", $path or exit 1;
Use die for error conditions. Reserve exit for the top level of
the program where you have decided, as the application, that the run
is over.
exit inside eval#
exit is not caught by eval. Unlike die, which unwinds to
the nearest eval and sets $@, exit walks straight past every
eval frame on the stack, runs END/DESTROY, and terminates.
eval { exit 5 }; # process exits 5; the eval block
print "after eval\n"; # never runs
If you are writing a plugin host or a test harness that must survive
misbehaved user code calling exit, there is no language-level
catch. The conventional workaround is to fork, let the child call
exit, and inspect the child’s status in the parent:
my $pid = fork // die "fork: $!";
if ($pid == 0) {
run_user_code(); # may call exit
exit 0;
}
waitpid $pid, 0;
my $status = $? >> 8;
Examples#
Early return from the program after a prompt:
my $ans = <STDIN>;
exit 0 if $ans =~ /^[Xx]/;
Exit with a status derived from a child process — extract the high
byte of $? so the shell sees the same code the child produced:
system @cmd;
exit $? >> 8 if $?;
Rewrite a status in an END block — whatever $? holds at the end
of cleanup is the exit status delivered to the parent:
END {
$? = 0 if $? == 2 && $ENV{IGNORE_MISUSE};
}
Bypass cleanup in a forked child so the parent’s destructors do not run twice:
use POSIX ();
my $pid = fork // die "fork: $!";
if ($pid == 0) {
exec @cmd;
POSIX::_exit(127); # exec failed; do NOT run parent's END
}
Edge cases#
exitwith no argument isexit 0. Many scripts rely on falling off the end of the file to get an implicit0; writingexit;makes the intent explicit.Non-integer argument:
EXPRis evaluated in scalar context and converted to an integer.exit "3x"exits3;exit "hello"exits0with a warning underuse warnings.Negative values are taken modulo 256 by the kernel.
exit -1appears to the shell as255. Pass only0..255to avoid the coercion.Values above 255 lose their high bits.
exit 256looks like success;exit 300looks likeexit 44. If you need to convey a larger value, write it to a file or toSTDERRand exit with a small status code.ENDblocks can cancel your status but not the exit itself. AnENDblock cannot stop the process from terminating — it can only change$?, and therefore the status seen by the parent.Global destruction order is not the reverse of construction. During the final sweep Perl walks package globals in an implementation-defined order. Do not rely on one
DESTROYrunning before another; if ordering matters, tear the objects down explicitly before callingexit.Inside a
BEGINblock,exitterminates the compilation phase and exits the process.ENDblocks already registered run; laterBEGIN/END/code in the file does not.Threads: in a program with multiple Perl interpreter threads,
exitterminates the whole process, not just the calling thread. Usethreads->exitfor per-thread exit.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
die— raise a trappable exception; the right choice for reporting errors from a subroutinewarn— emit a diagnostic without terminating; pairs withdiethe wayprintpairs withexitENDblocks — compile-time-registered cleanup code run in LIFO order on any exit, includingexit EXPRDESTROYmethods — per-object cleanup called during global destruction afterENDblocks have run$?— child-process / final exit status; visible to and mutable byENDblocks and destructorsPOSIX::_exit— immediate termination that bypassesENDandDESTROY; use in forked children and signal handlers