Python subproces.call无法按预期工作

时间:2013-02-02 10:08:12

标签: python subprocess

我无法让subprocess.call()正常工作:

>>> from subprocess import call
>>> call(['adduser', '--home=/var/www/myusername/', '--gecos', 'GECOS', '--disabled-login', 'myusername'], shell=True)
adduser: Only one or two names allowed.
1

但没有shell = True:

>>> call(['adduser', '--home=/var/www/myusername/', '--gecos', 'GECOS', '--disabled-login', 'myusername'])
Adding user `myusername' ...
Adding new group `myusername' (1001) ...
Adding new user `myusername' (1001) with group `myusername' ...
Creating home directory `/var/www/myusername/' ...
Copying files from `/etc/skel' ...
0

或直接在shell中使用:

root@www1:~# adduser --home=/var/www/myusername/ --gecos GECOS --disabled-login myusername
Adding user `myusername' ...
Adding new group `myusername' (1001) ...
Adding new user `myusername' (1001) with group `myusername' ...
Creating home directory `/var/www/myusername/' ...
Copying files from `/etc/skel' ...

我错过了shell = True行为中的一些逻辑。有人可以解释一下为什么吗?第一个例子有什么问题?从adduser命令错误消息看,参数似乎有些瘫痪。

谢谢!

4 个答案:

答案 0 :(得分:2)

指定shell = True时,切换到完全不同的行为。来自文档:

  

在Unix上,shell = True,shell默认为/ bin / sh。如果args是   string,string指定通过shell执行的命令。   这意味着字符串必须完全按照原样进行格式化   在shell提示符下键入时。这包括,例如,引用或   反斜杠转义文件名,其中包含空格。如果args是   sequence,第一项指定命令字符串,以及任何   其他项目将被视为shell的附加参数   本身。也就是说,Popen相当于:

     

Popen(['/ bin / sh',' - c',args [0],args [1],...])

所以你正在运行等效的

/bin/sh -c "adduser" --home=/var/www/myusername/ --gecos GECOS --disabled-login myusername

您获得的错误消息是当您尝试运行adduser而没有任何参数时会发生的情况,因为所有参数都传递给sh

如果你想设置shell = True,你需要像这样调用它:

call('adduser --home=/var/www/myusername/ --gecos GECOS --disabled-login myusername', shell=True)

或者像这样:

call(['adduser --home=/var/www/myusername/ --gecos GECOS --disabled-login myusername'], shell=True)

但大多数情况下,您只想在没有call的情况下使用shell=True并使用参数列表。按照你的第二个,工作,例子。

答案 1 :(得分:1)

我对此并不是100%肯定,但我认为你指定Shell=True,你应该将命令行作为shell本身将解释的单个字符串传递:

>>> call('adduser --home=/var/www/myusername/ --gecos GECOS --disabled-login myusername', shell=True)

答案 2 :(得分:0)

似乎使用shell=True,您需要将字符串传递给args而不是参数列表。

一个简单的测试:

In [4]: subprocess.call(['echo', 'foo', 'bar'], shell=True)

Out[4]: 0

In [5]: subprocess.call('echo foo bar', shell=True)
foo bar
Out[5]: 0

即。 echo只有在我使用字符串而不是列表时才能获得正确的参数。

Python版本2.7.3

答案 3 :(得分:0)

如果shell为True,则指定的命令将通过shell执行,即shell负责文件名通配符,环境变量扩展等。当你使用shell = True时,cmd是一个单独的字符串,它必须完全格式化因为它将在shell中输入。如果shell = True且cmd是一个序列,则第一个参数指定命令,其他参数被视为shell本身的参数(通过-c开关)。

如果shell = False,并且提供了一系列参数,模块将负责正确转义和引用参数,例如~将不会扩展为主目录等。

subprocess文档中阅读有关它的更多信息,并注意与shell = True相关的安全隐患。