A question about a list and subprocess.check_call()

Amirouche Boubekki amirouche.boubekki at gmail.com
Mon Feb 16 14:39:45 EST 2015


On Mon Feb 16 2015 at 7:40:42 PM Peter Otten <__peter__ at web.de> wrote:

> David Aldrich wrote:
>
> > Hi Peter
> >
> > Thanks very much for your reply. I have added one more question below.
> >
> >> The straightforward approach is to pass a list or tuple:
> >>
> >> def build(build_options=()):
> >>     subprocess_check_call(("make",) + build_options)
> >>
> >> build(("flagA=true", "flagB=true"))
> >
> > This looks fine - I am trying it.
> >
> > I would like to display on the console the entire make command, so I have
> > done this:
> >
> > def build(build_options=()):
> >         make_command = 'make '.join(map(build_options))
> >         print('Build command: ' + make_command)
> >         subprocess.check_call(("make",)+build_options)
> >
> > but I get error:
> >
> > make_command = 'make '.join(map(build_options))
> > TypeError: map() must have at least two arguments.
> >
> > What would be the correct way to concatenate and display the elements in
> > the tuple please?
>
> Hm, what do you expect map() to achieve? And "make " is not really the
> string you want as a separator...
>
> You can join the strings in build_options with
>
> >>> build_options = "foo", "bar", "baz"
> >>> " ".join(build_options)
> 'foo bar baz'
> >>> "make " + " ".join(build_options)
> 'make foo bar baz'
>
> But you shouldn't do this as you have already learnt that spaces do not
> separate arguments; in fact by default check_call() doesn't even use the
> shell. An example to drive the point home:
>
> >>> from subprocess import check_call
> >>> check_call(["python3", "-c", "import sys; print(sys.argv[1:])", "foo",
> "bar"])
> ['foo', 'bar']
> 0
> >>> check_call(["python3", "-c", "import sys; print(sys.argv[1:])", "foo
> bar"])
> ['foo bar']
>
> Both invocations would appear to issue the same command in your debugging
> print() call. list2cmdline() does a bit better; it resembles the command
> issued if the shell were used:
>
> >>> print(subprocess.list2cmdline(["make"] + build_options))
> make foo "bar baz"
>

It's also possible to do it the other around using shlex.split. I prefer
that version because I can easily copy/paste the command from code to the
shell, it's also more readable IMO:

> cmd = """python3 -O -c "import sys; print(sys.argv[1:])" foo bar "spam
egg" """
> print(cmd)
> subprocess.check_call(shlex.split(cmd))

shlex.split(cmd) must be prefered to cmd.split('') which doesn't take into
account shell strings. paths with space must be wrapped in quote (talking
of path, pathlib is awesome).

https://docs.python.org/2.7/library/shlex.html?highlight=shlex#shlex.split


Regards


>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20150216/372fb7d3/attachment.html>


More information about the Python-list mailing list