python中subprocess模块subprocess.run,subprocess.getoutput,subprocess.Popen、subprocess.call的使用

subprocess可以帮我们执行命令,获取执行结果及返回内容。

1、subprocess.run()

此方法为python3.5版本后的推荐方法,可以获取执行结果、返回内容等一些常用的信息, 满足大部分开发需要。

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

args: 要执行的命令。类型为str(如 “ls -l”)或包含str的list,tuple等(如 [“ls”, “-l”]), 推荐使用list形式,如果传入的args为str且包含参数,则 必须shell=True,默认为False。

**stdin、stdout、stderr: ** 子进程的标准输入、输出、错误,常用的为stdout,我们可以获取命令执行后的输出内容。

**shell:**如果该参数为 True,将通过操作系统的 shell 执行指定的命令,默认为False。

**timeout:**设置命令超时时间。如果命令执行时间超时,子进程将被杀死,并弹出 TimeoutExpired 异常。

**check:**如果该参数设置为 True,并且进程退出状态码不是 0,则弹 出 CalledProcessError 异常。

encoding: 如果指定了该参数,则 stdin、stdout 和 stderr 可以接收字符串数据,并以该编码方式编码。否则只接收 bytes 类型的数据。

capture_output: 设置为True,将捕获stdout和stderr,从而获执行命令后取返回的内容。

例:

# 当前文件夹下有 a.py、b.py、c.py 三个文件,我们执行 “ls -l”来获取一下文件信息
import subprocess

# args传入str的方式 有参数传入需shell=True,encoding可以指定capture_output(stdin、stdout、stderr)的编码格式
ret = subprocess.run('ls -l', shell=True, capture_output=True, encoding='utf-8')

# ret.returncode 返回int类型,0 则执行成功
print('ret.returncode: ',ret.returncode)
# ret.stdout 返回str类型,命令执行后的输出内容,可以按实际需求处理str, 这里简单做个split
print('ret.stdout: ', ret.stdout)
print('ret.stdout.split:', ret.stdout.split())

# 输出结果
ret.returncode:  0

ret.stdout:  总用量 0
-rw-r--r--. 1 root root 0 929 11:24 a.py
-rw-r--r--. 1 root root 0 929 11:24 b.py
-rw-r--r--. 1 root root 0 929 11:24 c.py

ret.stdout.split: ['总用量', '0', '-rw-r--r--.', '1', 'root', 'root', '0', '9月', '29', '11:24', 'a.py', '-rw-r--r--.', '1', 'root', 'root', '0', '9月', '29', '11:24', 'b.py', '-rw-r--r--.', '1', 'root', 'root', '0', '9月', '29', '11:24', 'c.py']

# args传入list的方式, 输出结果是一样的
ret = subprocess.run(['ls', '-l'], capture_output=True, encoding='utf-8')
print('ret.stdout: ', ret.stdout)

# 输出结果
ret.stdout:  总用量 0
-rw-r--r--. 1 root root 0 929 11:24 a.py
-rw-r--r--. 1 root root 0 929 11:24 b.py
-rw-r--r--. 1 root root 0 929 11:24 c.py

2、subprocess.getoutput()

该方法可以直接获取命令执行后的输出内容,返回值为str

import subprocess
cmd = 'ls -l'  
ret = subprocess.getoutput(cmd)

print(type(ret))
print(ret)


# 输出结果为
<class 'str'>

总用量 0
-rw-r--r--. 1 root root 0 929 11:24 a.py
-rw-r--r--. 1 root root 0 929 11:24 b.py
-rw-r--r--. 1 root root 0 929 11:24 c.py

3、subprocess.Popen()

Popen 是 subprocess的核心,底层的创建和管理逻辑都是基于它的。
使用Popen可以实现一些更复杂的逻辑。

import subprocess
cmd = 'ls -l'
ret = subprocess.Popen(cmd, shell=True)
print(ret)
# 输出  在使用ret.wait()或ret.poll()之前是获取不到 returncode 的
<Popen: returncode: None args: 'ls -l'>

# poll() 检查进程是否终止,如果终止返回 returncode,否则返回 None。
ret.poll()
print(ret)
# 输出 此时可以获取到ret.returncode
<Popen: returncode: 0 args: 'ls -l'>

Popen对象的方法:
poll(): 检查进程是否终止,如果终止返回 returncode,否则返回 None。
wait(timeout): 等待子进程终止。
communicate(input,timeout): 和子进程交互,发送和读取数据。
send_signal(singnal): 发送信号到子进程 。
terminate(): 停止子进程,也就是发送SIGTERM信号到子进程。
kill(): 杀死子进程。发送 SIGKILL 信号到子进程。

4、subprocess.call() 及 check_call()
subprocess.call() 为python3.5以前版本使用,与 subprocess.run()用法基本一致,但call()返回的为命令结束码,无法获取更多信息,不推荐使用,现已被run()取代。
subprocess.check_call() 与call()的区别为,check_call()如果命令失败(即 returncode不为0)会主动抛出subprocess.CalledProcessError异常,使用subprocess.run(check=True)可取代subprocess.check_call()。