5

Does running exec echo "some "; echo "test" in bash never print "some test"?

I would seek confirmation to this question, as I am writing a small shell script and I would like it to not contiue anything after the exec command has been called.

I think that I would not need to worry, as my understanding, after consulting:

  • man 3 exec
  • man 1p exec

The shell scripts, when executed by the shell will make

  1. the shell execute the program exec, which
  2. uses the exec*** family system calls that replace the shell/bash that which has been executing the script, by this impeding further actions of the shell (which was "replaced")

As laid out before, main goal of this question is to seek confirmation for my reasoning as to prevent that anything in the script occuring after the exec (such as echo test) would be executed.

I would appreciate a general answer (POSIX), as far as possible, but just in case of particularities I am most interested in GNU/Linux and GNU/Bash

3

exec does always finish the script if it executes a command and does so successfully (not related to the command's exit code but to starting it).

exec can be run without a command in a very useful way: To permanently redirect file descriptors:

exec 3>/path/to/file

If the command cannot be started then the shell behaviour depends on the configuration. bash exits by default.

It may be best for you to use a function instead:

safe_exec () {
    cmd="$1"
    if test -z "$cmd" || ! test -f "$cmd" || ! test -x "$cmd"; then
        exit 1
    else
        exec "$@"
    fi
}

safe_exec echo "some "; echo "test"
  • I had not considered the case of exec failing to "execute" the command/program (e.g. for the it not being in path or else). I also appreciated the answer with the safe_exec(), which I have to confirm yet to be without bashisms, as else bash -as mentioned by you exits on fail by default. thank you – humanityANDpeace Nov 26 '17 at 16:13
  • @humanityANDpeace safe_exec would have to be modified for finding commands in PATH. – Hauke Laging Nov 26 '17 at 17:23
  • safe_exec seems more complicated than necessary: wouldn't exec "$@"; exit 1 work just as well? (Actually, better, since it avoids the problem of commands in PATH not being found.) – hvd Nov 26 '17 at 22:37
  • Your safe_exec doesn't work as written as it doesn't look up the path of the executable before testing for -z/-f/-x... Even if it did, note that contrary to exec, it could cause an EXIT trap to be executed. – Stéphane Chazelas Nov 26 '17 at 23:07
  • The case where bash fails to execve the command is a bit more complicated than indicated in this answer. After the failure it first does a bunch of things to try and work around the failing execve in an attempt to deal with badly formatted scripts. Secondly whether it exits or continues by default depends on whether it is an interactive shell (at least on Ubuntu 14.04 it does). – kasperd Nov 27 '17 at 0:03
6

Right, if exec succeeds, it replaces the current shell, so the following commands are not, err.. executed.

However, at least in Bash, the shell also exits if the exec fails:

exec [-cl] [-a name] [command [arguments]]

If command is supplied, it replaces the shell without creating a new process. [...] If command cannot be executed for some reason, a non-interactive shell exits, unless the execfail shell option is enabled. In that case, it returns failure.

So even something like bash -c 'exec /bin/nosuchfile; echo foo' will just print an error message about the missing program file. To handle the error in the script, you'd need something like

#!/bin/bash
shopt -s execfail
exec /someprogram
echo whoops, it failed

But, you still get the error message from exec. If you put a redirection on the exec, it stays in effect if the script continues after the exec failed.

  • 2
    That's also a POSIX requirement. exec being a special builtin its failure (at least when non-interactive) is required to be fatal. – Stéphane Chazelas Nov 26 '17 at 23:00
5

The exec builtin (with a command argument¹) replaces the shell process². No subsequent code in the shell process is executed.

Thus the only way exec echo "some "; echo "test" would print some text is if there was an executable command called echo in the PATH, and this executable printed some text rather than some. It cannot happen under normal circumstances where the echo executable behaves as one would expect from a command called echo.

If there is no executable file called echo in the PATH or executing it fails, then exec will display an error message and exit the shell. Even in that case, echo "test" is not executed.

¹ exec without a command argument is a different beast. It doesn't replace the shell process, it just applies redirections.
² In a subshell, only the subshell is affected, the parent shell keeps running normally.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.