I'm making a python script, that wraps call to docker run by creating a child process with pexpect (pexpect is essential to me, because command might be interactive):
import argparse
import pexpect
parser = argparse.ArgumentParser()
parser.add_argument("some_positional_argument")
parser.add_argument("command", nargs=argparse.REMAINDER)
args = parser.parse_args()
command = " ".join(args.command)
docker_run = f"docker run -it --rm ubuntu {command}"
print(f"docker_run: {docker_run}")
child = pexpect.spawn(docker_run)
child.interact()
child.close()
exit(child.exitstatus)
Problem is, when passing bash command with quotes to the command argument, python will interpret it as just a string value, so quotes will be gone:
python3 t.py foo bash -c 'echo hi'
docker_run: docker run -it --rm ubuntu bash -c echo hi
# empty line here, because 'bash -c echo' was actually called inside the container
What is interesting to me, how docker solves this issue internally? Because docker run is similar CLI program, that will receive same unquoted echo hi. Example
docker run --rm -it ubuntu bash -c 'echo hi'
hi
works just fine.
I tried to look into docker cli source code:
- https://github.com/docker/cli/blob/06de1f8d2c56737ea06a547197a5ae3701aa5397/cli/command/container/run.go#L44
- https://github.com/docker/cli/blob/06de1f8d2c56737ea06a547197a5ae3701aa5397/cli/command/container/run.go#L108
parse function seemed promising:
- https://github.com/docker/cli/blob/06de1f8d2c56737ea06a547197a5ae3701aa5397/cli/command/container/opts.go#L324
- https://github.com/docker/cli/blob/06de1f8d2c56737ea06a547197a5ae3701aa5397/cli/command/container/opts.go#L402
- https://github.com/docker/cli/blob/06de1f8d2c56737ea06a547197a5ae3701aa5397/cli/command/container/opts.go#L632
- https://github.com/docker/cli/blob/06de1f8d2c56737ea06a547197a5ae3701aa5397/cli/command/container/opts.go#L716
but i didn't find any post processing (like adding quotes back) of the arguments.
Python has a utility to give shell-like quote handling, shlex, https://pymotw.com/2/shlex/ (or officil python docs)
So replace
with
to get properly quoted text.