subprocess.call() arguments ignored when using shell=True w/ list [duplicate]

倖福魔咒の 提交于 2019-11-26 21:10:57

When shell is True, the first argument is appended to ["/bin/sh", "-c"]. If that argument is a list, the resulting list is

["/bin/sh", "-c", "ls", "-al"]

That is, only ls, not ls -al is used as the argument to the -c option. -al is used as the first argument the shell itself, not ls.

When using shell=True, you generally just want to pass a single string and let the shell split it according the shell's normal word-splitting rules.

# Produces ["/bin/sh", "-c", "ls -al"]
subprocess.call("ls -al", shell=True)

In your case, it doesn't see like you need to use shell=True at all.

When you use shell=True with a list, extra arguments are passed to the shell itself, not to the command running in the shell. They can then be referred to from within the shell script (passed as argv[0]) as $0, $1, etc.

The easiest answer is "don't do that": If you want to pass a list, don't use shell=True; if you want to pass a string, always use shell=True.


That said, it is possible to form your command in such a way as to read those arguments. The below is an example that violates my above rule -- a command you couldn't implement[*] without shell=True (and /bin/sh provided by bash), because it relies on bash's built-in version of printf (which supports %q as an extension):

subprocess.call([
    "printf '%q\\n' \"$0\" \"$@\"",
    'these strings are\r\n',
    '"shell escaped" in the output from this command',
    "so that they can *safely* be run through eval"
], shell=True)

[*] - Not really true; one could use /bin/bash as argv[0] with shell=False to implement this more reliably, as it would then no longer depend on your /bin/sh being bash.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!