官方推荐使用
subprocess.run() 函数
或者
subprocess.Peopen()类
转载自https://www.cnblogs.com/zhou2019/p/10582716.html
总结
那么我们到底该用哪个模块、哪个函数来执行命令与系统及系统进行交互呢?下面我们来做个总结:
- 首先应该知道的是,Python2.4版本引入了subprocess模块用来替换os.system()、os.popen()、os.spawn*()等函数以及commands模块;也就是说如果你使用的是Python 2.4及以上的版本就应该使用subprocess模块了。
- 如果你的应用使用的Python 2.4以上,但是是Python 3.5以下的版本,Python官方给出的建议是使用subprocess.call()函数。Python 2.5中新增了一个subprocess.check_call()函数,Python 2.7中新增了一个subprocess.check_output()函数,这两个函数也可以按照需求进行使用。
- 如果你的应用使用的是Python 3.5及以上的版本(目前应该还很少),Python官方给出的建议是尽量使用subprocess.run()函数。
当subprocess.call()、subprocess.check_call()、subprocess.check_output()和subprocess.run()这些高级函数无法满足需求时,我们可以使用subprocess.Popen类来实现我们需要的复杂功能。
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
subprocess.getstatusoutput(cmd)
subprocess.getoutput(cmd)
1. subprocess.call()
其参数可以是一个字符串,也可以是一个列表
- 返回值是进程的返回值
- 子进程的输出直接输出到当前的进程输出上
- 返回值非0,不会抛出异常
>>> import subprocess
>>> rescode=subprocess.call("pwd")
/root
>>> rescode=subprocess.call(["ls", "*.log"])
ls: cannot access *.log: No such file or directory
>>> print(rescode)
2
>>> rescode=subprocess.call(args=["echo","python"],timeout=20)
python
如果命令超时会收到subprocess.TimeoutExpired的错误
2. subprocess.check_all()
和subprocess.call的区别是
- 返回值非0,会抛出异常CalledProcessError错误
>>> rescode=subprocess.check_call(["rm","python.txt"])
rm: cannot remove ‘python.txt’: No such file or directory
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/python3/lib/python3.7/subprocess.py", line 363, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['rm', 'python.txt']' returned non-zero exit status 1.
>>>
>>> rescode
1
3. subprocess.check_output()
特点是,
- 返回值就是子进程的输出,输出是bytes类型
- 同时获取标准输出和标准错误输出,加上参数stderr=subprocess.STDOUT
- 命令返回非0,会报错
演示:
创建一个叫stdout_err.sh的shell脚本
脚本内容如下
echo "stdout content"
echo "stderr content" 1>&2
exit 0
将标准输出定向到stdout.txt, 错误输出定向到stderr.txt
[root@i-5529xjeg ~]# bash stdout_err.sh 1>stdout.txt 2>stderr.txt
[root@i-5529xjeg ~]# cat stderr.txt
stderr content
[root@i-5529xjeg ~]# cat stdout.txt
stdout content
如果不合并标准错误输出到标准输出
>>> get_res=subprocess.check_output(['bash','stdout_err.sh'])
stderr content
>>> get_res
b'stdout content
'
>>>
如果合并标准错误输出到标准输出
>>> get_res=subprocess.check_output(['bash','stdout_err.sh'],stderr=subprocess.STDOUT)
>>> get_res
b'stdout content
stderr content
'
>>>
4. subprocess.getoutput()
这个指有输出,不检查返回值
- 不用担心python抛出错误
- 没有返回值相关的信息
>>> get_res=subprocess.getoutput('bash stdout_err.sh')
>>> get_res
'stdout content
stderr content'
>>> get_res=subprocess.getoutput('fadsfad')
>>> get_res
'/bin/sh: fadsfad: command not found'
>>>
5. subprocess.getstatusoutput()
这个比较好
- 不用担心python抛出异常
- 有子进程的返回值
- 有子进程的标准输出和标准错误输出
- 返回一个元组,第一个值是返回值
>>> get_res=subprocess.getstatusoutput('ls nonexist.txt')
>>> get_res
(2, 'ls: cannot access nonexist.txt: No such file or directory')
>>>
6. subprocess.Popen() 类
6.1 args参数是一个字符串的时候必须是可以执行的
如"ls -l"或者"echo python"都会报错
>>> get_res=subprocess.Popen('echo python')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/python3/lib/python3.7/subprocess.py", line 800, in __init__
restore_signals, start_new_session)
File "/usr/local/python3/lib/python3.7/subprocess.py", line 1551, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'echo python': 'echo python'
>>>
加上shell=True就正常
>>> get_res=subprocess.Popen('echo python',shell=True)
python
>>>
6.2 不加shell=True,需要使用列表传入
>>> get_res=subprocess.Popen(['echo','python'])
python
>>> get_res
<subprocess.Popen object at 0x7f6f92e306d0>
>>>
输出定向到文件, 新建test.py文件
import time,os,sys
import subprocess
fd_stdout=open("a.txt","w+")
po_obj=subprocess.Popen("date",shell=True,stdout=fd_stdout)
time.sleep(1)
fd_stdout.close()
fd_r=open("a.txt","r")
content=fd_r.read()
print(u"a.txt包含的内容",content)
fd_r.close()
如果希望直接得到子进程的输出,而不是通过打开一个文件,可以设定stdout为subprocess.PIPE
上面的例子可以修改为
import time,os,sys
import subprocess
po_obj=subprocess.Popen("date",shell=True,stdout=subprocess.PIPE)
time.sleep(1)
content=po_obj.stdout.read()
print(u"a.txt包含的内容",content)
类似的也可以设置stdin,这样就可以给子进程输入数据了
6.3 实例对象的wait()方法
>>> import subprocess
>>> po_obj=subprocess.Popen("sleep 1000",shell=True)
>>> po_obj.returncode is None
True
>>> po_obj.pid
5658
>>> import os
>>> os.system("ps 5658")
PID TTY STAT TIME COMMAND
5658 pts/0 S+ 0:00 sleep 1000
0
>>> po_obj.kill()
>>> os.system("ps 5658")
PID TTY STAT TIME COMMAND
5658 pts/0 Z+ 0:00 [sleep] <defunct> #Z+ 表示僵尸状态
0
>>> r=po_obj.wait() #处理僵尸进程
>>> os.system("ps 5658") #进程已经不在了
PID TTY STAT TIME COMMAND
256
>>> r #查看wait()的返回值,就是进程的返回值
-9
>>> po_obj.returncode #另外一种方式查看进程的返回值
-9
>>>