12.13. subprocess模块

参考文献: https://blog.51cto.com/u_14320361/2491366

常用方法实例

12.13.1. call()

执行命令,并返回状态码,状态码0代表命令执行成功,其他的都表示命令执行不成功

>>> ret = subprocess.call(["ls", "-l"], shell=False)
>>> ret
0

另一种执行方式
# shell=True表示调用原生的shell命令去执行
>>> ret = subprocess.call("ls -l", shell=True)
>>> ret
0

12.13.2. check_call()

执行命令,如果执行状态码是0,则返回0,否则抛异常

# 执行一个正确的命令就会返回执行结果和状态码
>>> subprocess.check_call(["ls", "-l"])
-rw-r--r-- 1 root root 172 May 25 21:21 file.conf
0

# 如果执行的是一个错误的命令,那么就会返回错误信息
>>> subprocess.check_call(["ls", "a"])
ls: cannot access a: No such file or directory
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/subprocess.py", line 505, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['ls', 'a']' returned non-zero exit status 2

12.13.3. check_output()

执行命令,如果状态码是0,则返回执行结果,否则抛异常

# 执行成功就把执行的结果赋值给变量V
>>> V = subprocess.check_output("python -V", shell=True)

# 执行错误的命令就会输出异常
>>> subprocess.check_output("pasas", shell=True)
'pasas' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python35\lib\subprocess.py", line 629, in check_output
    **kwargs).stdout
  File "C:\Python35\lib\subprocess.py", line 711, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'pasas' returned non-zero exit status 1

以上的三种执行方式在执行命令的时候,shell默认等于True,等于True的时候,括号内的命令是一行的,如果shell等于False,那么[]内的字符串就是命令的一个元素,执行的时候会把[]内的字符串拼接起来执行。

12.13.4. call、check_call、check_output

protest.py

import subprocess
print('call() test:',subprocess.call(['python','protest.py']))
print('')
print('check_call() test:',subprocess.check_call(['python','protest.py']))
print('')
print('getstatusoutput() test:',subprocess.getstatusoutput(['python','protest.py']))
print('')
print('getoutput() test:',subprocess.getoutput(['python','protest.py']))
print('')
print('check_output() test:',subprocess.check_output(['python','protest.py']))

输出结果:

Hello World!
call() test: 0

Hello World!
check_call() test: 0

getstatusoutput() test: (0, 'Hello World!')

getoutput() test: Hello World!

check_output() test: b'Hello World!\r\n'

12.13.5. subprocess.Popen()初探

  • call()、check_call()、check_output()默认内部调用的都是subprocess.Popen(),而subprocess.Popen()则用于执行更复杂的系统命令。

参数

参数

说明

stdin

标准输入

stdout

标准输出

stderr

错误句柄

cwd

用于设置子进程的当前目录

env

用于指定子进程的环境变量

  • 执行普通命令

>>> subprocess.Popen("Python -V", shell=True)
# Python 3.5.1是输出出来的结果
>>> Python 3.5.1
  • 执行命令分为两种:

输入即可得到输出,如:ifconfig
输入进行某交互式环境,依赖再输入,如:python
>>> import subprocess
# 先进入'/tmp'目录,然后在创建subprocess文件夹,shell=True可有可无
>>> subprocess.Popen("mkdir subprocess", shell=True, cwd='/tmp',)

>>> import os
>>> os.system("ls /tmp")
subprocess

12.13.6. subprocess.Popen()实例

# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# 执行标准输入,write后面是输入的命令
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
# 输入之后关闭
obj.stdin.close()

# 读取标准输出的内容,赋值给cmd_out对象
cmd_out = obj.stdout.read()
# 关闭标准输出
obj.stdout.close()

# 读取错误输出的内容,赋值给cmd_error对象
cmd_error = obj.stderr.read()

# 关闭错误输出
obj.stderr.close()

# 输出内容
print(cmd_out)
print(cmd_error)
# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# 执行两条命令
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")

# communicate把错误输出或者标准输出的内容赋值给out_error_list对象,如果有错误就赋值错误输出,否则就复制标准输出
out_error_list = obj.communicate()

# 输出out_error_list对象的内容
print(out_error_list)
# 导入subprocess模块
import subprocess

# 执行python命令,进入python解释器,stdin标准输入、stdout标准输出、stderr错误输出,universal_newlines=True自动输入换行符
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
# 直接执行print("hello")命令,然后把错误或者正确的结果赋值给out_error_list对象
out_error_list = obj.communicate('print("hello")')

# 输出out_error_list对象的内容
print(out_error_list)
import subprocess
s=subprocess.Popen('sleep 20', shell=True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)

print(s.wait())                 # 阻塞等待子进程完成并返回状态码 shell 0为正确  但管道内容过多会造成死锁可以用 communicate()
print(s.stdout.read())
print(s.stderr.read())

print(s.communicate())            # 返回元组 (stdout, stderr)  会阻塞等待进程完成 推荐使用
print(s.returncode)             # 返回执行状态
#!/usr/bin/env python
#-*- coding:utf8 -*-
import subprocess
prcs = subprocess.Popen(['python','test.py'],
                        stdout=subprocess.PIPE,
                        stdin=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        universal_newlines=True,
                        shell=True)
prcs.communicate("These strings are from stdin.")
print("subprcess pid: .", prcs.pid)
print('\nSTDOUT: ')
print(str(prcs.communicate()[0]))
print('STDERR: ')
print(str(prcs.communicate()[1]))

输出信息:

subprcess pid: . 1492

STDOUT:
hello world
this is subprocess test....!

STDERR:

12.13.7. 上交花束小测试

实现进程之间传输数据。

进程之间互相通信。

#!/usr/bin/env python
#-*- coding:utf8 -*-
# auther; 18793
# Date:2019/6/26 11:37
# filename: subprocess上交花束.py
import subprocess
processes = []
psum =5

for i in range(psum):
    processes.append(subprocess.Popen(['python', 'protest9.py'],
                                      stdout=subprocess.PIPE,
                                      stdin=subprocess.PIPE,
                                      universal_newlines=True,
                                      shell=True))

processes[0].communicate('0 bouquet of flowers!')
for before,after in zip(processes[:psum],processes[1:]):
    after.communicate(before.communicate()[0])
print("\n Sum of Processes: %d" % psum)
print()
for item in processes:
    print(item.communicate()[0])

protest9.py

#!/usr/bin/env python
#-*- coding:utf8 -*-
# auther; 18793
# Date:2019/6/26 11:41
# filename: protest9.py
a = input()
a = a.split(" ")
a[0] = str(int(a[0])+1)
print(" ".join(a))

输出结果

 Sum of Processes: 5

1 bouquet of flowers!

2 bouquet of flowers!

3 bouquet of flowers!

4 bouquet of flowers!

5 bouquet of flowers!

subprocess模块执行外部命令

def execute_cmd(cmd):
    prcs = subprocess.Popen(cmd,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
    stdout, stderr = prcs.communicate()
    if prcs.returncode != 0:
        return prcs.returncode, stderr

    return (prcs.returncode, prcs.stdout)
def exec_cmd(cmd):
    """
    Execute arbitrary commands as sub-processes.
    """
    proc = subprocess.Popen(cmd,
                            stdout=subprocess.PIPE,
                            stdin=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            universal_newlines=True,
                            shell=True)
    stdout, stderr = proc.communicate()
    return (proc.returncode, stdout, stderr)

12.13.8. Python3 subprocess

https://www.runoob.com/w3cnote/python3-subprocess.html

12.13.9. Popen 对象方法

  • poll(): 检查进程是否终止,如果终止返回 returncode,否则返回 None。

  • wait(timeout): 等待子进程终止。

  • communicate(input,timeout): 和子进程交互,发送和读取数据。

  • send_signal(singnal): 发送信号到子进程 。

  • terminate(): 停止子进程,也就是发送SIGTERM信号到子进程。

  • kill(): 杀死子进程。发送 SIGKILL 信号到子进程。

import time
import subprocess

def cmd(command):
    subp = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,encoding="utf-8")
    subp.wait(2)
    if subp.poll() == 0:
        print(subp.communicate()[1])
    else:
        print("失败")

cmd("java -version")
cmd("exit 1")

12.13.10. python执行linux系统命令的几种方法

1. 使用os.system

仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息

2. 使用os.popen

该方法不但执行命令还返回执行后的信息对象,好处在于:将返回的结果赋于一变量,便于程序的处理。

cmd = os.popen('df -h').read().split('\n')

3. 使用模块 subprocess

https://ansheng.me/python-standard-library-subprocess/