Python执行外部命令subprocess

来自CloudWiki
跳转至: 导航搜索

Linux中的使用

subprocess.run()是官方推荐使用的方法,几乎所有的工作都可以由它来完成。首先来看一下函数原型:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,
shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)

该函数返回一个CompletedProcess类(有属性传入参数及返回值)的实例,虽然该函数的参数有很多,但是我们只需要知道几个常用的就可以了。

  • args代表需要在操作系统中执行的命令,可以是字符串形式(要求shell=True),也可以是列表list类型。
  • *代表可变参数,一般是列或字典形式。
  • stdin、stdout、stderr指定了可执行程序的标准输入、标准输出、标准错误文件句柄。
  • shell代表着程序是否需要在shell上执行,当想使用shell的特性时,设置shell=True,这样就可以使用shell指令的管道、文件名称通配符、环境变量等,不过Python也提供了许多类shell的模块,如glob、fnmatch、os.walk()、os.path.expandvars()、os.path.expanduser()和shutil。
  • check如果check设置为True,就检查命令的返回值,当返回值为非0时,将抛出CalledProcessError异常。
  • timeout设置超时时间,如果超时,则强制kill掉子进程。

执行命令

在Linux系统中如果我们执行一个Linux命令并获取它的返回值,可有如下两种方法,

方法一

>>> import subprocess
>>> a=subprocess.run("ls -l /dev/null",shell=True)
crw-rw-rw- 1 root root 1, 3 Feb  9 17:23 /dev/null
>>> a
CompletedProcess(args='ls -l /dev/null', returncode=0)
>>> a.args
'ls -l /dev/null'
>>> a.returncode
0

方法二

>>> import subprocess
>>> b=subprocess.run(["ls","-l","/dev/null"])
crw-rw-rw- 1 root root 1, 3 Feb  9 17:23 /dev/null
>>> b
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0)
>>> b.args
['ls', '-l', '/dev/null']
>>> b.returncode
0

执行脚本

[root@localhost ~]# chmod 777 /root/test.sh
[root@localhost ~]# sudo python3
Python 3.7.5 (default, Apr 16 2020, 22:32:00) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> s= subprocess.run(['/root/test.sh'])
Hello World
>>> s
CompletedProcess(args=['/root/test.sh'], returncode=0)
>>> s.args
['/root/test.sh']
>>> s.returncode
0

捕获脚本输出

>>> a=subprocess.run("ls -l /dev/null",shell=True,stdout=subprocess.PIPE)
>>> a
CompletedProcess(args='ls -l /dev/null', returncode=0, stdout=b'crw-rw-rw- 1 root root 1, 3 Feb  9 17:23 /dev/null\n')
>>> a.stdout
b'crw-rw-rw- 1 root root 1, 3 Feb  9 17:23 /dev/null\n'

捕获执行异常

如果传入参数check=True,当returncode不为0时,将会抛出subprocess.CalledProcessError异常;

如果传输timeout参数,当运行时间超过timeout时就会抛出TimeoutExpired异常

>>> a=subprocess.run("exit 1",shell=True,check=True)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Python3/lib/python3.6/subprocess.py", line 418, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1.

>>> a=subprocess.run("sleep 1",shell=True,timeout=2)

>>> a=subprocess.run("sleep 3",shell=True,timeout=2)

Traceback (most recent call last):
  File "/usr/local/Python3/lib/python3.6/subprocess.py", line 405, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "/usr/local/Python3/lib/python3.6/subprocess.py", line 843, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/local/Python3/lib/python3.6/subprocess.py", line 1540, in _communicate
    self.wait(timeout=self._remaining_time(endtime))
  File "/usr/local/Python3/lib/python3.6/subprocess.py", line 1449, in wait
    raise TimeoutExpired(self.args, timeout)
subprocess.TimeoutExpired: Command 'sleep 3' timed out after 1.9999209220113698 seconds

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Python3/lib/python3.6/subprocess.py", line 410, in run
    stderr=stderr)
subprocess.TimeoutExpired: Command 'sleep 3' timed out after 2 seconds
>>>


Windows中的使用

使用subprocess模块可以方便地执行操作系统支持的命令,可与其他应用程序结合使用。因此,Python也常被称为胶水语言。

>>> a=subprocess.run('ipconfig',shell=True,stdout=subprocess.PIPE,encoding="gb2312")

>>> a.stdout

其中encoding指定了windows的编码方式。

>>> a=subprocess.run('dir',shell=True,stdout=subprocess.PIPE,encoding="gb2312")

>>> a.stdout