35

In a Linux bash script such as:

exec /usr/lib/4.5/mono-service.exe ./AudioVideoRecorder.exe "$@"

, why do I have to exec the command and not just run it without the exec part?

Petr Skocik
  • 28,816
Frank
  • 681
  • 2
    exec in shell scripts tells interpreter to replace itself with the program it runs. –  May 30 '16 at 05:27
  • And your question is unclear... –  May 30 '16 at 05:28
  • @siblynx, Thank you for your comments. I intended to contrast exec in shell scripts with similar or alternative ways to do this which do not require the exec keyword. – Frank May 30 '16 at 05:32

1 Answers1

39

The short answer is: you don't, but it saves about 1ms of CPU time (on modern CPUs). (Note that you should exec only at the end of a script, because nothing after the exec will get run).

The longer answer is: Exec replaces the process image of the current process with the process image of the executable you exec. That means that the moment you exec, the shell process that does the execing gets completely destroyed and replaced by the execed program. When you don't exec, the shell forks itself, execs in the fork, and waits around for the child process to exit, collecting its return status, in the hope there might be additional commands to run afterwards (fork + exec is the standard procedure by which new commands get spawned). Since there are none, the fork is a complete waste of time and you might as well exec directly and save on that forking time.

For most intents and purposes, it's essentially a microoptimization based on the knowledge of how process get spawned on Unices.


Note: (thanks to ilkkachu) Where it makes a slight semantic difference is if the process spawning the script cares about how the maybe-exec'ed program dies. If the maybe-exec'ed child exits normally, the exec and non-exec form are equivalent since the shell script forwards the last waited-on exit status to its own exit status. If, however, the child dies from signal n, then the shell would convert that to exit status 128+n, effectively losing the was-signaled information. (The information is not lost if you're sure the child never regularly exits with an exit code >128, which is usually the case.). When you do exec, there's no middleman shell anymore, and the exit status info goes directly to the caller of the execing script (and the info about whether the child exited or was signaled is preserved, as there's no middleman shell to merge it into an exit code). (See waitpid(2) for more information).

Petr Skocik
  • 28,816
  • 6
    One more addition: exec saves one pid and some small amounts of memory required to store shell image (if there is only one left) and some process metadata about it because shell does not exist and does not wait for forked process to complete. This maybe critical in embedded systems with 16M or even 8M onboard RAM available. –  May 30 '16 at 05:49
  • @siblynx, I appreciate your excellent observation. – Frank May 30 '16 at 06:06
  • 5
    Since exec replaces the shell in place, it also makes the executed program a direct child of the shell's parent, instead of a grandchild through the shell. That might matter if the program running the script (and ultimately the exec'd program) cares about how its child dies – ilkkachu May 30 '16 at 06:47
  • @ikkachu Excellent point. I'll add it to the answer if you don't mind. – Petr Skocik May 30 '16 at 06:49
  • @Jasper exec something vs just something are the two options – Petr Skocik May 30 '16 at 09:23
  • @Jasper Edited the note. Hopefully, it should be clearer now. – Petr Skocik May 30 '16 at 09:38
  • @PSkocik Yes, thanks, that definitely helps for my understanding. – Jasper May 30 '16 at 09:45
  • I have a scenario in which a script calls an executable with exec. When this executable crashes, I want to use valgrind – Sander Mertens Dec 08 '17 at 22:37