0

我无法让 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

4 回答 4

2

当您指定 shell=True 时,您会切换到完全不同的行为。从文档:

在 shell=True 的 Unix 上,shell 默认为 /bin/sh。如果 args 是字符串,则该字符串指定要通过 shell 执行的命令。这意味着字符串的格式必须与在 shell 提示符下键入时的格式完全相同。这包括,例如,引用或反斜杠转义文件名,其中包含空格。如果 args 是一个序列,则第一项指定命令字符串,任何附加项都将被视为 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=Trueand 的情况下使用参数列表。按照你的第二个,工作,例子。

于 2013-02-02T10:19:38.833 回答
1

我不是 100% 确定这一点,但我认为如果你指定Shell=True,你应该将命令行作为 shell 本身将解释的单个字符串传递:

>>> call('adduser --home=/var/www/myusername/ --gecos GECOS --disabled-login myusername', shell=True)
于 2013-02-02T10:18:56.133 回答
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

于 2013-02-02T10:19:04.497 回答
0

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

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

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

于 2013-02-02T10:19:06.720 回答