如何在Python中调用外部命令?

为了在python env中运行外部命令,或者启动守护进程,或者也许调用命令并捕获其输出,Python支持多种调用外部命令的方法

是否需要保留命令的输出,或将输入发送到命令,或控制其生命周期,取决于方法的要求。

Subprocess

Subprocess是python(3.5 +版本)中推荐的模块,用于执行外部命令。使用subprocess模块的call方法,可以在python函数内调用外部命令。

Python 3.6.8 (default, Apr 25 2019, 21:02:35)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import subprocess
>>> subprocess.call(['ls', '-l'])
total 8
drwxr-xr-x 4 XXXXX sw 4096 Oct  1 17:37 python_samples
drwxr-xr-x 5 XXXXX sw 4096 Sep 29 19:53 venv
0
>>>

将输出重定向到文件

为了将输出重定向到文件,请使用with函数打开文件并使用stdout参数。

Python 3.6.8 (default, Apr 25 2019, 21:02:35)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import subprocess
>>> with open('output.txt', 'w') as f:
...     subprocess.call(['whoami'], stdout=f)
...
>>> exit()-bash-4.2$ more output.txt
User

将参数作为输入从stdin传递到命令

使用 call()。打开文件并使用stdin参数传递句柄。

-bash-4.2$ python3
Python 3.6.8 (default, Apr 25 2019, 21:02:35)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import subprocess
>>> with open('output.txt', 'r') as f:
...     subprocess.call(['more'], stdin =f)
...
user
>>>

使用shell = True,可以将shell命令传递给 call() 函数。

-bash-4.2$ python3
Python 3.6.8 (default, Apr 25 2019, 21:02:35)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import subprocess
>>> subprocess.call('ls -la', shell=True)
total 20
drwxr-xr-x 4 sradhakr sw 4096 Oct 17 15:42 .
drwxr-xr-x 8 sradhakr sw 8192 Oct  8 13:40 ..
-rw-r--r-- 1 sradhakr sw    9 Oct 17 15:42 output.txt
drwxr-xr-x 4 sradhakr sw 4096 Oct  1 17:37 python_samples
drwxr-xr-x 5 sradhakr sw 4096 Sep 29 19:53 venv
>>>

如果命令来自不受信任的来源,则使用shell = True会带来安全风险。例如,使用用户输入,如果我们收到诸如rm –rf /之类的命令,则对于文件系统可能是危险的命令。

为了捕获字符串中的命令输出,请使用 subprocess.check_output()

import subprocess

try:
    output = subprocess.check_output(input('enter command >> '), shell=True)    print(output)exceptsubprocess.CalledProcessErroras e:
    print('exception with returncode: {}, command: {}, output = {}'.format(e.returncode, e.cmd, e.output))

输出结果

enter command >> whoami
b'user\n'

exit 命令代码

exit命令决定命令处理的成败。call()的返回值是退出代码,它决定命令处理的结果。

Python 3.6.8 (default, Apr 25 2019, 21:02:35)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> import subprocess
>>> print("return code {}".format(subprocess.call('ls -la', shell=True)))
total 20
drwxr-xr-x 4 sradhakr sw 4096 Oct 17 15:42 .
drwxr-xr-x 8 sradhakr sw 8192 Oct  8 13:40 ..
-rw-r--r-- 1 sradhakr sw    9 Oct 17 15:42 output.txt
drwxr-xr-x 4 sradhakr sw 4096 Oct  1 17:37 python_samples
drwxr-xr-x 5 sradhakr sw 4096 Sep 29 19:53 venv
return code 0

为了获得关于外部命令处理的额外信息,还有一个名为subprocess.check_call()的额外方法。

import subprocess
try:
    print(subprocess.check_call(['cat','random.txt']))
exceptsubprocess.CalledProcessErroras e:
     print('exception: returncode: {}, command: {}'.format(e.returncode, e.cmd))

输出结果

cat: random.txt: No such file or directory
exception: returncode: 1, command: ['cat', 'random.txt']