我在使用python subprocess.check_call()
函数时遇到了一个非常奇怪的错误。这里有两个测试,由于权限问题都应该失败,但第一个只返回'usage'(“意外行为”):
# Test #1
import subprocess
subprocess.check_call(['git', 'clone', 'https://github.com/achedeuzot/project',
'/var/vhosts/project'], shell=True)
# Shell output
usage: git [--version] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
[-c name=value] [--help]
<command> [<args>]
The most commonly used git commands are:
[...]
现在进行第二次测试(“预期行为”):
# Test #2
import subprocess
subprocess.check_call(' '.join(['git', 'clone', 'https://github.com/achedeuzot/project',
'/var/vhosts/project']), shell=True)
# Here, we're making it into a string, but the call should be *exactly* the same.
# Shell output
fatal: could not create work tree dir '/var/vhosts/project'.: Permission denied
第二个错误是正确的错误。我确实没有权限。但为什么这两个电话之间有区别?我认为使用单个字符串或列表与check_call()
函数相同。我已经阅读了python documentation和各种用法示例,看起来都是正确的。
有人有同样的奇怪错误吗?或者有人知道为什么在命令完全相同时输出会有差异吗?
附注:Python 3.4
答案 0 :(得分:3)
从第一个中删除shell=True
。如果仔细阅读子进程模块文档,您将看到。如果shell=False
(默认),则第一个参数是带有参数和all的命令行列表(或者只包含命令的字符串,根本不提供任何参数)。如果shell = True,那么第一个参数是一个表示shell命令行的字符串,执行一个shell,然后为你解析命令行并按空格分割(+更危险的事情,你可能不希望它做)。 如果shell=True
且第一个参数是列表,则第一个列表项是shell命令行,其余的作为参数传递给shell,而不是命令。
除非你确实真的需要,否则总是让shell=False
。
答案 1 :(得分:0)
这里是文档中的相关位:
如果args是一个序列,则第一个项指定命令字符串,并且任何其他项将被视为shell本身的附加参数。也就是说,Popen相当于:
Popen(['/bin/sh', '-c', args[0], args[1], ...])