pythonbashdockerargparsepexpect

How to keep quotes in arguments passed to a python script when using argparse, pexpect and docker?


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.


Solution

  • 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.