How to escape and store shell command line arguments into one argument?

Inb4 anyone saying this is a bad idea, it’s actually a reasonable approach for things like this.

I’m writing this Docker container that can execute user provided commands through contained OpenVPN connection in Docker, e.g. docker run vpntunnel curl example.com.

So the ENTRYPOINT of the image will fire up OpenVPN, after the VPN tunnel is up, execute the user provided CMD line.

Problem is, the standard way to run commands after OpenVPN is up is through the --up option of OpenVPN. Here is the man page description of this option:

--up cmd
  Run command cmd after successful TUN/TAP device open (pre --user UID change).
  cmd consists of a path to script (or executable program), optionally followed
  by arguments. The path and arguments may be single- or double-quoted and/or
  escaped using a backslash, and should be separated by one or more spaces.

So the reasonable approach here is for ENTRYPOINT script to correctly escape the user provided CMD line and pass the whole thing as one parameter to --up option of OpenVPN.

In case my Docker image needs to perform some initializations after the tunnel is up and before the user command line is executed, I can prepend a script before the user provided CMD line like this: --up 'tunnel-up.sh CMD...' and in the last line of tunnel-up.sh use "[email protected]" to execute user provided arguments.

Now as you may guess, the only problem left is how to correctly escape an entire command line to be able to passed as a single argument.

The naive approach is just --up "tunnel-up.sh [email protected]" but it surely can’t distinguish command lines between a b c and "a b" c.

Source: StackOverflow