Use case / practical example for Bash' builtin exec
exec
is often used in shell scripts which mainly act as wrappers for starting other binaries. For example:
#!/bin/sh
if stuff;
EXTRA_OPTIONS="-x -y -z"
else
EXTRA_OPTIONS="-a foo"
fi
exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"
so that after the wrapper is finished running, the "real" binary takes over and there is no longer any trace of the wrapper script that temporarily occupied the same slot in the process table. The "real" binary is a direct child of whatever launched it instead of a grandchild.
You mention also I/O redirection in your question. That is quite a different use case of exec
and has nothing to do with replacing the shell with another process. When exec
has no arguments, like so:
exec 3>>/tmp/logfile
then I/O redirections on the command line take effect in the current shell process, but the current shell process keeps running and moves on to the next command in the script.
I've used a shell exec
builtin to get a process ID (PID) to a Java program. There may be a way to get PID from inside Java now, but several years ago, there was not. Once a process has its own PID, it can write that out to a PID file (look in /var/run/
for file names with a '.pid' suffix) to allow management programs to know the PID of the running process, and to prevent a second instance of the same server from running. It works something like this:
exec java -cp=YourServer.jar StartClass -p $$
Code in the main()
method of class StartClass
handles argument parsing and can find its own process ID.
For fun, run the following program (translated to your implementation language of choice) in the background on a system with user process accounting and limits.
while(true) fork();
Now that every slot in the process table that you are permitted to use is full of copies of that running program, how do you intend to kill it? Launching kill(1) requires another process slot, which you can't have. It sure would be handy to have the shell replace itself with the kill command...
exec /bin/kill -9 -1
(Assumes your system has kill(1) at /bin/kill. "exec `which kill` -9 -1" is potentially safer.) This sends SIGKILL to every process you can.
(Note: Don't log out from your launching shell unless the process limits always permit a new login a process slot for its shell. This can be a bit more difficult to clean up if you do. I certainly did not do this in the early '90s. Nope.)