I've been seeing this in a lot of docker-entrypoint.sh
scripts recently, and can't find an explanation online. My first thoughts are that it is something to do with signaling but that's a pretty wild guess.
-
Thanks! I don't know why I didn't add docker-entrypoint parts to my search queries! If a mod wants to lock/delete this they can, just felt it was more appropriate to ask here.– John Von NeumannSep 5, 2018 at 12:20
3 Answers
The "$@"
bit will expand to the list of positional parameters (usually the command line arguments), individually quoted to avoid word splitting and filename generation ("globbing").
The exec
will replace the current process with the process resulting from executing its argument.
In short, exec "$@"
will run the command given by the command line parameters in such a way that the current process is replaced by it (if the exec
is able to execute the command at all).
-
So it's a way of hot-swapping the purpose of a process? So instead of allowing it to die, we just repurpose it for something else? Sep 5, 2018 at 16:20
-
1@JohnVonNeumann Yes, and it makes the signal handling easier to handle as Stephen Kitt wrote in his answer.– Kusalananda ♦Sep 5, 2018 at 16:36
-
It's funny, I'm studying my Linux Foundation SysAdmin atm and I literally just got to a section describing this procedure. You made it a lot easier to understand. I'd never really thought of running bash commands as spawning new processes, dunno what I did think, but it hadn't occurred that that's the way it works. Sep 5, 2018 at 17:12
-
@JohnVonNeumann Yes, that's what happens in shell scripts, except for when executing built-in commands such as
printf
andtrue
etc. (unless the external version of these are explicitly used).– Kusalananda ♦Sep 5, 2018 at 17:20
"$@"
in Bourne-like shells, in list contexts expands to all the positional parameters as separate arguments.
In a script, initially, the positional parameters are the arguments that the script itself received.
exec
is to run a command in the same process as the shell. That's the last command a script will execute because after that, the process will be running another command than the shell.
So if your script is
#! /bin/sh -
exec "$@"
And you call your script using a shell command line like:
/path/to/your-script 'echo' "some test" 'x y'
It will call exec
with echo
, some test
, and x y
as arguments which will execute echo
(in most sh
implementations, /bin/echo
as opposed to the echo
shell builtin) in the same process that was previously running the shell interpreting your script with some test
and x y
as arguments.
-
So if I'm understanding this correctly, basically, you can use it to say, run a script multiple times with a variety of arguments? Or have I completely missed it? Sep 5, 2018 at 16:19
Two other answers explain what exec "$@"
does. This answer on Stack Overflow explains why it’s important for Docker, and as you surmise, it does have to do with signals:
This is important in Docker for signals to be proxied correctly. For example, if Redis was started without
exec
, it will not receive aSIGTERM
upondocker stop
and will not get a chance to shutdown cleanly. In some cases, this can lead to data loss or zombie processes.If you do start child processes (i.e. don't use
exec
), the parent process becomes responsible for handling and forwarding signals as appropriate. This is one of the reasons it's best to usesupervisord
or similar when running multiple processes in a container, as it will forward signals appropriately.