298

Can anyone explain what are the uses of the exec command in shell scripting with simple examples?

slm
  • 15,396
  • 12
  • 109
  • 124
user2400564
  • 4,619
  • 7
  • 24
  • 27
  • 33
    The links to linux.about.com are not helpful. They don't make it remotely clear how executing a command or pipeline of commands using 'exec' differs from just executing them normally. Hence the OP's question "what is the use of exec"? – Jonathan Hartley Apr 28 '14 at 13:43
  • [The Uses of the Exec Command in Shell Script](https://www.baeldung.com/linux/exec-command-in-shell-script) Is this link helpful? – hunknownz Nov 24 '21 at 12:37

2 Answers2

324

The exec built-in command mirrors functions in the kernel, there are a family of them based on execve, which is usually called from C.

exec replaces the current program in the current process, without forking a new process. It is not something you would use in every script you write, but it comes in handy on occasion. Here are some scenarios I have used it;

  1. We want the user to run a specific application program without access to the shell. We could change the sign-in program in /etc/passwd, but maybe we want environment setting to be used from start-up files. So, in (say) .profile, the last statement says something like:

     exec appln-program
    

    so now there is no shell to go back to. Even if appln-program crashes, the end-user cannot get to a shell, because it is not there - the exec replaced it.

  2. We want to use a different shell to the one in /etc/passwd. Stupid as it may seem, some sites do not allow users to alter their sign-in shell. One site I know had everyone start with csh, and everyone just put into their .login (csh start-up file) a call to ksh. While that worked, it left a stray csh process running, and the logout was two stage which could get confusing. So we changed it to exec ksh which just replaced the c-shell program with the korn shell, and made everything simpler (there are other issues with this, such as the fact that the ksh is not a login-shell).

  3. Just to save processes. If we call prog1 -> prog2 -> prog3 -> prog4 etc. and never go back, then make each call an exec. It saves resources (not much, admittedly, unless repeated) and makes shutdown simplier.

You have obviously seen exec used somewhere, perhaps if you showed the code that's bugging you we could justify its use.

Edit: I realised that my answer above is incomplete. There are two uses of exec in shells like ksh and bash - used for opening file descriptors. Here are some examples:

exec 3< thisfile          # open "thisfile" for reading on file descriptor 3
exec 4> thatfile          # open "thatfile" for writing on file descriptor 4
exec 8<> tother           # open "tother" for reading and writing on fd 8
exec 6>> other            # open "other" for appending on file descriptor 6
exec 5<&0                 # copy read file descriptor 0 onto file descriptor 5
exec 7>&4                 # copy write file descriptor 4 onto 7
exec 3<&-                 # close the read file descriptor 3
exec 6>&-                 # close the write file descriptor 6

Note that spacing is very important here. If you place a space between the fd number and the redirection symbol then exec reverts to the original meaning:

  exec 3 < thisfile       # oops, overwrite the current program with command "3"

There are several ways you can use these, on ksh use read -u or print -u, on bash, for example:

read <&3
echo stuff >&4
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
cdarke
  • 42,728
  • 8
  • 80
  • 84
  • 27
    there's also another use I found quite handy and worth mentioning here because it relates to python web applications and seems something in between your (awesome) answers 2 and 3. I usually run wsgi web apps (say django or flask) through [supervisor](http://supervisord.org/running.html) calling a [gunicorn](http://gunicorn.org/) app: the latter notoriously requiring quite a few environment variables, it's way easier and more maintainable running gunicorn from a shell script that sets everything up and eventually `exec gunicorn` giving the correct pid back to supervisor. – gru Feb 08 '15 at 17:21
  • 1
    The docs do say that `exec` can be used for redirection: > If command is not specified, any redirections take effect in the current shell, and the return status is 0. If there is a redirection error, the return status is 1. But _how_ does `exec` actually work to change a file descriptor? Why is this particular command chosen for this task? (Markdown is failing right now?) – Ray Mar 19 '15 at 23:34
  • @Ray: best I can do it: http://pubs.opengroup.org/onlinepubs/009604599/utilities/exec.html . If you need to know how then look at the shell source code. – cdarke Mar 20 '15 at 16:43
  • 7
    Another use: Redirect all a script's output to a logfile `exec >.\logfilename.log 2>&1` – Hogan Apr 15 '15 at 18:26
  • Yes, it means execute the command specified on the command-line. Look-up the `@` variable in `man bash`. The `exec` replaces the current program with a new one, again, look-up `exec` in the man pages. – cdarke Jul 07 '16 at 07:55
  • Related follow-up question: https://stackoverflow.com/questions/41603122/understanding-exec-in-bash – Kvass Jan 12 '17 at 00:20
  • Could you please explain `exec &> /var/log/userdata.log`, when followed by other commands such as yum install? It seems to me that it causes commands to be outputted to log file instead of being executed – Carmageddon Feb 28 '19 at 20:03
  • 1
    @Carmageddon: `&>` is a `bash` extension (see `man bash`) and your example is equivalent to `exec >/var/log/userdata.log 2>&1`. In other words it redirects stdout and stderr to that file. Commands that follow will inherit those redirections unless they are reset, but they will be executed. – cdarke Feb 28 '19 at 22:37
65

Just to augment the accepted answer with a brief newbie-friendly short answer, you probably don't need exec.

If you're still here, the following discussion should hopefully reveal why. When you run, say,

sh -c 'command'

you run a sh instance, then start command as a child of that sh instance. When command finishes, the sh instance also finishes.

sh -c 'exec command'

runs a sh instance, then replaces that sh instance with the command binary, and runs that instead.

Of course, both of these are useless in this limited context; you simply want

command

There are some fringe situations where you want the shell to read its configuration file or somehow otherwise set up the environment as a preparation for running command. This is pretty much the sole situation where exec command is useful.

#!/bin/sh
ENVIRONMENT=$(some complex task)
exec command

This does some stuff to prepare the environment so that it contains what is needed. Once that's done, the sh instance is no longer necessary, and so it's a (minor) optimization to simply replace the sh instance with the command process, rather than have sh run it as a child process and wait for it, then exit as soon as it finishes.

Similarly, if you want to free up as much resources as possible for a heavyish command at the end of a shell script, you might want to exec that command as an optimization.

If something forces you to run sh but you really wanted to run something else, exec something else is of course a workaround to replace the undesired sh instance (like for example if you really wanted to run your own spiffy gosh instead of sh but yours isn't listed in /etc/shells so you can't specify it as your login shell).

The second use of exec to manipulate file descriptors is a separate topic. The accepted answer covers that nicely; to keep this self-contained, I'll just defer to the manual for anything where exec is followed by a redirect instead of a command name.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Thanks tripleee for the excellent reply and vote up. Wondering for the two ways I could execute -- (1) `bash -c ""`, (2) `bash -c "exec "`, then after the execution I check the return status by using `$?`, wondering if there are any differences? Are in both cases `$?` tracking if the `` is successful? Or tracking if shell itself is ok? – Lin Ma Jul 26 '16 at 05:20
  • 2
    Resisting the temptation to call your own spiffy shell `bush`. Of course, this applies to `bash` or generally any popular Unix shell as well; though as @anishsane [notes](http://stackoverflow.com/a/37851568/874188), Bash secretly optimizes `bash -c 'command'` by actually doing `exec command`. – tripleee Jul 26 '16 at 05:21
  • 1
    The exit code of the shell is generally the exit code of the last command it executed. Of course, if the shell fails to run, or to execute the command, the shell's exit status will reflect that with a suitable error code. – tripleee Jul 26 '16 at 05:25
  • Thanks tripleee, vote up for both posts, and wondering if `exec` understand bash conditional execution like `||` and `&&`? Thanks. – Lin Ma Jul 26 '16 at 05:43
  • 1
    Following up with tangential questions should be avoided. Thanks. A little experimentation would reveal what happens when you try `bash -c 'exec nonesvch || echo still here'` (hint: it doesn't `echo` and the exit code is 127). – tripleee Jul 26 '16 at 05:55
  • 1
    There is no point in `sh -c command` in my book; you could just as well write `command` and it would have essentially the same effect, with one less process. So, the first section of this answer really isn't helpful — as you go on to admit. You can use `exec` to terminate the script and replace it with whatever command you execute; this cuts down the number of processes and gets the shell out of the loop when reporting the exit status. – Jonathan Leffler Jul 26 '16 at 06:05
  • 3
    @JonathanLeffler I am deliberately documenting an antipattern which I see in newbie questions. This one was prompted by [this duplicate](http://stackoverflow.com/questions/38580978/difference-between-running-a-bash-command-with-and-without-exec) but I have seen it before, so I wanted to cover that specifically. – tripleee Jul 26 '16 at 06:07
  • 1
    Then you need to clarify the first paragraph — a lot. That isn't how it reads at the moment. It currently says "you don't need `exec command` because you can use `sh -c command` instead". If that isn't what you want it to say, you have to revise the language to make it 100% explicit. Lemme know when you've revised it. – Jonathan Leffler Jul 26 '16 at 06:09
  • 2
    @JonathanLeffler Minor wording tweak; is this sufficient, do you think? Thanks for the feedback. – tripleee Jul 26 '16 at 06:12
  • 1
    Better, but ... well, you might want to use `exec command` when the command is the last statement in the script — instead of just `command`. I think I'd prefer a bigger rewrite. – Jonathan Leffler Jul 26 '16 at 06:22
  • 2
    Thanks - I added another brief paragraph about this optimization. It's not really clear to me if you have other objections, or if you would just like to explain things from a different angle. – tripleee Jul 26 '16 at 06:30
  • 2
    Another useful use of `exec` is to patch the arguments. Let me give an example. libvirt/xapi calls qemu with some standard arguments. If I want to patch some arguments on the fly, I move `/path/to/qemu` to `/path/to/qemu.bin`; create a shell script at `/path/to/qemu` with contents: `a=("$@"); add_remove_modify_arguments_in_array_a; exec /path/to/qemu.bin "${a[@]}"` – anishsane Jan 24 '21 at 13:11