赞
踩
subprocess – 创建附加进程
subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口。用于替换如下模块:
os.system() , os.spawnv() , os和popen2模块中的popen()函数,以及 commands().
subprocess模块,替换os.system等
subprocess.run(['df','-h']) 当参数传,Python解析,如果有管道符就不行了
subprocess.run('df -h | grep sda1', shell=True) shell=True是指不需要Python解析,直接把字符串给shell
Python3.5才出现subprocess.run
终端输入的命令分为两种:
输入即可得到输出,如:ifconfig
输入进行某环境,依赖再输入,如:Python
常用subprocess
没有管道
retcode = subprocess.call(['ls','-l']) 成功返回0,不成功返回非0
subprocess.check_call(['ls','-l']) 执行成功返回0,执行错误抛异常
subprocess.getoutput('ls /bin/ls')接收字符串格式命令,只返回结果
res = subprocess.check_output(['ls','-l'])执行成功返回执行结果,不成功出错
subprocess.getstatsoutput('ls /bin/ls') 返回元祖(1,'/bin/ls'),第一个状态,第二个结果
上面的方法,底层都是封装subprocess.popen
例子
res = subprocess.popen('ifconfig | grep 192',shell=True)
res
<subprocess.popen object at ox7f2131a>
res.stdout.read()读不出来
要读出来要先输出到标准输出里,先存到管道PIPE 再给stdout python和shell是两个进程不能独立通信,必须通过操作系统提供的管道
用管道可以把结果存到stdin stdout stderr
subprocess.popen('ifconfig | grep 192',shell=True,stdout=subprocess.PIPE)
res.stdout.read()就可以读出来了
subprocess.popen('ifconfig | gr1111ep 192',shell=True,stdout=subprocess.PIPE)
出错会直接打印错误。想不打印错误可以stderr保存stderr=subprocess.PIPE
poll() check if child process has terminated. returns returncode
---------
res=subprocess.popen("sleep 10;echo 'hello'", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
执行的时候没反应,不知道是卡主了还是执行完了
每次调subprocess执行Linux命令,都相当于启动了一个新的shell,启动新的进程,执行一次命令等结果
如果该命令要花半小时,不知道是卡主了还是执行完了,可以res.poll()返回none表示还没有执行完,返回0表示执行完了
res.wait()等待结束然后返回0
----------
terminate()杀掉该进程,res.terminate()
wait() wait for child process to terminate. returns returncode attribute
communicate()等待任务结束 没什么用,用Python当参数,输Python进入环境
stdin 标准输入
stdout 标准输出
stderr 标准错误
pid the process ID of the child process
-----可用参数
args: shell命令,可以是字符串或者序列类型
bufsize:指定缓冲,0无缓冲,1 行缓冲,其他 缓冲区大小 负值 系统缓冲
stdin,stdout,stderr:标准输入,输出,错误句柄
preexec_fn:只在Unix平台下有效,用于指定一个可执行对象,它将在子进程运行之前被调用
close_sfs:在Windows平台下,如果close_sfs被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道
所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误
shell:同上
cod:用于设置子进程的当前目录
env:用于指定子进程的环境变量。如果env=None,子进程的环境变量将从父进程中继承
universal_newlines:不同系统的换行符不同,True->同意使用\n
startupinfo与createionflags只在Windows下有效
将被传递给底层的createprocess()函数,用于设置子进程的一些属性,
如:主窗口的外观,进程的优先级等
subprocess实现sudo自动输入密码
例如Python里面执行sudo apt-get install vim (Linux里面要输入密码)
linux中应该echo '123' | sudo -S iptables -L
python直接 subprocess.popen("echo '123' | sudo -S iptables -L",shell=True)
1. 运行外部命令
subprocess.call(command) 方法
subprocess的call方法可以用于执行一个外部命令,但该方法不能返回执行的结果,只能返回执行的状态码: 成功(0) 或 错误(非0)
call()方法中的command可以是一个列表,也可以是一个字符串,作为字符串时需要用原生的shell来执行:
- import subprocess
- #执行 df -hl 命令
- #方法1:
- >>> subprocess.call(['ls','-l'])
- total 8
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
- 0
- #方法2:
- >>> subprocess.call("ls -l",shell=True)
- total 8
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
- 0
- >>> output = subprocess.call("ls -l",shell=True)
- total 8
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
- >>> print(output)
- 0
2. 错误处理
subprocess.check_call() 方法
我们说过call执行返回一个状态码,我们可以通过check_call()函数来检测命令的执行结果,如果不成功将返回 subprocess.CalledProcessError 异常
- >>> try:
- subprocess.check_call("ls -t", shell=True)
- except subprocess.CalledProcessError as err:
- print("Command Error")
-
- /bin/sh: lt: command not found
- Command Error
3. 捕获输出结果
subprocess.check_output() 方法
call()方法启动的进程,其标准输入输出会绑定到父进程的输入和输出。调用程序无法获取命令的输出结果。但可以通过check_output()方法来捕获输出。
- # 以下测试为python3.4下运行结果
- >>> output=subprocess.check_output("ls -l",shell=True)
- >>> output
- b'total 8\ndrwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem\ndrwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp\n'
- >>> print(output.decode('utf-8'))
- total 8
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
- try:
- output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
- except subprocess.CalledProcessError as err:
- print("Command Error", err)
-
- # 执行结果
- Command Error Command 'lT -l' returned non-zero exit status 127
subprocess.Popen()方法
函数call(), check_call() 和 check_output() 都是Popen类的包装器。直接使用Popen会对如何运行命令以及如何处理其输入输出有更多控制。如通过为stdin, stdout和stderr传递不同的参数。
输出结果(读)
- # 直接执行命令输出到屏幕
- >>> subprocess.Popen("ls -l",shell=True)
- <subprocess.Popen object at 0x7febd4175198>
- >>> total 12
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- -rw-rw-r-- 1 ws ws 8 Feb 25 10:38 test
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
-
- # 不输出到屏幕,输出到变量
- >>> proc = subprocess.Popen(['echo','"Stdout"'],stdout=subprocess.PIPE)
- # communicate返回标准输出或标准出错信息
- >>> stdout_value = proc.communicate()
- >>> stdout_value
- (b'"Stdout"\n', None)
-
- >>> proc = subprocess.Popen(['ls','-l'],stdout=subprocess.PIPE)
- >>> stdout_value = proc.communicate()
- >>> stdout_value
- (b'total 8\ndrwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem\ndrwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp\n', None)
- >>>
- >>> print((stdout_value[0]).decode('utf-8'))
- total 8
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
-
- #将结果输出到文件
- >>> file_handle = open("/home/ws/t.log",'w+')
- >>> subprocess.Popen("ls -l",shell=True,stdout=file_handle)
- t.log:
- drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
- -rw-rw-r-- 1 ws ws 8 Feb 25 10:38 test
- -rw-rw-r-- 1 ws ws 0 Feb 25 11:24 t.log
- drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

2 与进程的双向通信
- >>> proc = subprocess.Popen('cat', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- >>> msg = 'Hello world'.encode('utf-8')
- # 写入到输入管道
- >>> proc.stdin.write(msg)
- 11
- >>> stdout_value = proc.communicate()
- >>> stdout_value
- (b'Hello world', None)
-
- # 在需要进行相互交互的输入输出过程也可以使用shtin来实现
- # 以下实现打开python3的终端,执行一个print命令
- >>>proc = subprocess.Popen(['python3'],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
- >>>proc.stdin.write('print("helloworld")'.encode('utf-8'))
- >>>out_value,err_value=proc.communicate()
- >>>print(out_value)
- >>> print(out_value)
- b'helloworld\n'
- >>> print(err_value)
- b''

捕获错误输出
- >>> proc = subprocess.Popen(['python3'],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
- >>> proc.stdin.write('print "helloworld"'.encode('utf-8'))
- 18
- >>> out_value,err_value=proc.communicate()
- >>> out_value
- b''
- >>> print(err_value.decode('utf-8'))
- File "<stdin>", line 1
- print "helloworld"
- ^
- SyntaxError: Missing parentheses in call to 'print'
Popen其它方法
Popen.returncode 获取子进程状态码,0表示子进程结束,None未结束
在使用Popen调用系统命令式,建议使用communicate与stdin进行交互并获取输出(stdout),这样能保证子进程正常退出而避免出现僵尸进程。看下面例子
- >>> proc = subprocess.Popen('ls -l', shell=True, stdout=subprocess.PIPE)
- # 当前子进程ID
- >>> proc.pid
- 28906
- # 返回状态为None,进程未结束
- >>> print(proc.returncode)
- None
- # 通过communicate提交后
- >>> out_value = proc.communicate()
- >>> proc.pid
- 28906
- # 返回状态为0,子进程自动结束
- >>> print(proc.returncode)
- 0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。