python模块系列之 - subprocess

悠悠 2022-08-20 11:18 336阅读 0赞

subprocess – 创建附加进程
subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口。用于替换如下模块:
os.system() , os.spawnv() , os和popen2模块中的popen()函数,以及 commands().

1. 运行外部命令
subprocess.call(command) 方法
subprocess的call方法可以用于执行一个外部命令,但该方法不能返回执行的结果,只能返回执行的状态码: 成功(0) 或 错误(非0)
call()方法中的command可以是一个列表,也可以是一个字符串,作为字符串时需要用原生的shell来执行:

  1. import subprocess
  2. #执行 df -hl 命令
  3. #方法1:
  4. >>> subprocess.call(['ls','-l'])
  5. total 8
  6. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  7. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
  8. 0
  9. #方法2:
  10. >>> subprocess.call("ls -l",shell=True)
  11. total 8
  12. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  13. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
  14. 0

如上实例所示,虽然我们能看到执行的结果,但实际获取的值只是状态码

  1. >>> output = subprocess.call("ls -l",shell=True)
  2. total 8
  3. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  4. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
  5. >>> print(output)
  6. 0

2. 错误处理
subprocess.check_call() 方法
我们说过call执行返回一个状态码,我们可以通过check_call()函数来检测命令的执行结果,如果不成功将返回 subprocess.CalledProcessError 异常

  1. >>> try:
  2. subprocess.check_call("ls -t", shell=True)
  3. except subprocess.CalledProcessError as err:
  4. print("Command Error")
  5. /bin/sh: lt: command not found
  6. Command Error

3. 捕获输出结果
subprocess.check_output() 方法

call()方法启动的进程,其标准输入输出会绑定到父进程的输入和输出。调用程序无法获取命令的输出结果。但可以通过check_output()方法来捕获输出。

  1. # 以下测试为python3.4下运行结果
  2. >>> output=subprocess.check_output("ls -l",shell=True)
  3. >>> output
  4. 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'
  5. >>> print(output.decode('utf-8'))
  6. total 8
  7. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  8. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

以下例子将chek_output()方法执行命令异常时的错误捕获,而避免输出到控制台.

  1. try:
  2. output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
  3. except subprocess.CalledProcessError as err:
  4. print("Command Error", err)
  5. # 执行结果
  6. Command Error Command 'lT -l' returned non-zero exit status 127

直接处理管道
subprocess.Popen()方法

函数call(), check_call() 和 check_output() 都是Popen类的包装器。直接使用Popen会对如何运行命令以及如何处理其输入输出有更多控制。如通过为stdin, stdout和stderr传递不同的参数。

  1. 与进程的单向通信
    通过Popen()方法调用命令后执行的结果,可以设置stdout值为PIPE,再调用communicate()获取结果
    返回结果为tuple. 在python3中结果为byte类型,要得到str类型需要decode转换一下

输出结果(读)

  1. # 直接执行命令输出到屏幕
  2. >>> subprocess.Popen("ls -l",shell=True)
  3. <subprocess.Popen object at 0x7febd4175198>
  4. >>> total 12
  5. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  6. -rw-rw-r-- 1 ws ws 8 Feb 25 10:38 test
  7. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
  8. # 不输出到屏幕,输出到变量
  9. >>> proc = subprocess.Popen(['echo','"Stdout"'],stdout=subprocess.PIPE)
  10. # communicate返回标准输出或标准出错信息
  11. >>> stdout_value = proc.communicate()
  12. >>> stdout_value
  13. (b'"Stdout"\n', None)
  14. >>> proc = subprocess.Popen(['ls','-l'],stdout=subprocess.PIPE)
  15. >>> stdout_value = proc.communicate()
  16. >>> stdout_value
  17. (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)
  18. >>>
  19. >>> print((stdout_value[0]).decode('utf-8'))
  20. total 8
  21. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  22. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp
  23. #将结果输出到文件
  24. >>> file_handle = open("/home/ws/t.log",'w+')
  25. >>> subprocess.Popen("ls -l",shell=True,stdout=file_handle)
  26. t.log:
  27. drwxrwxr-x 4 ws ws 4096 Nov 25 13:50 MonitorSystem
  28. -rw-rw-r-- 1 ws ws 8 Feb 25 10:38 test
  29. -rw-rw-r-- 1 ws ws 0 Feb 25 11:24 t.log
  30. drwxrwxr-x 2 ws ws 4096 Feb 19 10:09 tmp

2 与进程的双向通信

  1. >>> proc = subprocess.Popen('cat', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  2. >>> msg = 'Hello world'.encode('utf-8')
  3. # 写入到输入管道
  4. >>> proc.stdin.write(msg)
  5. 11
  6. >>> stdout_value = proc.communicate()
  7. >>> stdout_value
  8. (b'Hello world', None)
  9. # 在需要进行相互交互的输入输出过程也可以使用shtin来实现
  10. # 以下实现打开python3的终端,执行一个print命令
  11. >>>proc = subprocess.Popen(['python3'],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
  12. >>>proc.stdin.write('print("helloworld")'.encode('utf-8'))
  13. >>>out_value,err_value=proc.communicate()
  14. >>>print(out_value)
  15. >>> print(out_value)
  16. b'helloworld\n'
  17. >>> print(err_value)
  18. b''

Popen.communicate()方法用于和子进程交互:发送数据到stdin,并从stdout和stderr读数据,直到收到EOF。等待子进程结束。

捕获错误输出

  1. >>> proc = subprocess.Popen(['python3'],stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,)
  2. >>> proc.stdin.write('print "helloworld"'.encode('utf-8'))
  3. 18
  4. >>> out_value,err_value=proc.communicate()
  5. >>> out_value
  6. b''
  7. >>> print(err_value.decode('utf-8'))
  8. File "<stdin>", line 1
  9. print "helloworld"
  10. ^
  11. SyntaxError: Missing parentheses in call to 'print'

Popen其它方法

  1. Popen.pid 查看子进程ID
  2. 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

发表评论

表情:
评论列表 (有 0 条评论,336人围观)

还没有评论,来说两句吧...

相关阅读

    相关 python模块系列 - subprocess

    subprocess – 创建附加进程 subprocess模块提供了一种一致的方法来创建和处理附加进程,与标准库中的其它模块相比,提供了一个更高级的接口。用于替换如下模块