2020-02-13 执行外部命令subprocess

1. 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掉子进程。

示例1:在Linux系统中执行一个脚本并获取它的返回值。

方法一:

>>> import subprocess
>>> a=subprocess.run("ls -l /dev/null", shell=True)
crw-rw-rw-. 1 root root 1, 3 Feb  7 17:53 /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  7 17:53 /dev/null
>>> b
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0)
>>> b.args
['ls', '-l', '/dev/null']
>>> b.returncode
0

如果要捕获脚本的输出,可以使用以下方法:

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

如果传入参数check=True,当returncode不为0时,将会抛出subprocess.CalledProcessError异常;如果传输timeout参数,当运行时间超过timeout时就会抛出TimeoutExpired异常。运行结果如下:

>>> a=subprocess.run("exit 1",check=True)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 403, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 709, in __init__
    restore_signals, start_new_session)
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 1344, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'exit 1': 'exit 1'
>>> a=subprocess.run("exit 1",shell=True,check=True)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/python3.6.5/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 3",shell=True,timeout=2)
Traceback (most recent call last):
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 405, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 843, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 1540, in _communicate
    self.wait(timeout=self._remaining_time(endtime))
  File "/usr/local/python3.6.5/lib/python3.6/subprocess.py", line 1449, in wait
    raise TimeoutExpired(self.args, timeout)
subprocess.TimeoutExpired: Command 'sleep 3' timed out after 1.9998847030074103 seconds

During handling of the above exception, another exception occurred:

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

一个任务不确定什么时间完成,可以设置一个超时时间,如果超时仍未完成,可以通过代码控制超时重新运行。如果超时重试3次不成功,就让程序报错退出。

2. Popen类

Popen类的构造函数

class subprocess.Popen( args,
  bufsize=0,
  executable=None,
  stdin=None,
  stdout=None,
  stderr=None,
  preexec_fn=None,
  close_fds=False,
  shell=False,
  cwd=None,
  env=None,
  universal_newlines=False,
  startupinfo=None,
  creationflags=0)
Popen类构造函数的参数

使用方法如下:

subprocess.Popen(["cat","abc.txt"])
subprocess.Popen("cat abc.txt")

这两个方法,后者将不会工作。因为如果是一个字符串的话,就必须是程序的路径才可以。(考虑unix的api函数exec,接受的是字符串列表)。但是下面的可以工作:

subprocess.Popen("cat abc.txt",shell=True)

这是因为它相当于:

subprocess.Popen(["/bin/sh","-c","cat abc.txt"])
Popen类对象的方法

3. 其他方法

(1)subprocess.call(*popenargs,**kwargs):call方法调用Popen()执行程序,并等待它完成。
(2)subprocess.check_call(*popenargs,**kwargs):调用前面的call(),如果返回值非零,则抛出异常。
(3)subprocess.check_output(*popenargs,**kwargs):调用Popen()执行程序,并返回其标准输出。

你可能感兴趣的:(2020-02-13 执行外部命令subprocess)