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:
parse function seemed promising:
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
" ".join(args.command)
with
shlex.join(args.command)
to get properly quoted text.