subprocess模块的使用小结

  • 引言

  subprocess是python中用于管理子进程的模块。在你写终端小工具时,你或许会需要它。它能很方便的把现成终端工具拼接起来,能轻易的获得多核cpu的加持,极大的提高你的效率。

 

  • 背景知识

      在聊这个模块前,先对一些背景概念做一些解释。

 

  进程:计算机中的程序关于某数据集合上的一次运行活动。你可以把进程类比为烹饪中做一道菜的过程。食谱就是程序,你就是cpu,做各种菜的原料就是输入的数据。进程就是你阅读食谱,取来各种原料,烹饪这道菜的一系列动作的总和。

 

  管道:管道是进程间的通信方式。可以理解为两个进程使用一个管子把彼此连接起来,发起通信的一方把数据注入管子里,另一方从管里获取数据。

 

  Shell注入:Shell注入又被称之为OS命令注入,它指的是利用程序所存在的漏洞,构建含有恶意指令的字符串使目标程序执行攻击者的命令。如果知道木马屠城记,想想那只木马吧。
 
  • 典型的使用方式(代码使用python 3.9编写,操作系统为linux)

   最简单的使用方式,run方法

   例子1 新建一个进程使用echo命令输出‘hello world’

1 import subprocess
2 
3 subprocess.run(['echo', 'Hello world'])

  

  例子2  使用check参数检查进程执行的结果,进程以非零状态码退出则抛出异常

1 import subprocess
2 
3 try:
4     subprocess.run(['false'], check=True)
5 except subprocess.CalledProcessError as err:
6     print('ERROR:', err)

  

  例子3 通过capture_output参数捕获子进程的输出(包括标准输出stdout和标准错误输出stderr),供后面的程序使用

1 import subprocess
2 
3 result = subprocess.run(['cat', 'file'], capture_output=True, encoding='utf-8')
4 msg, err = result.stdout, result.stderr
5 print(msg, err)
6 print(msg.count("8"))

 

  例子4 使用shell参数,指定shell执行命令。这里命令可以直接使用字符串,而不必使用字符串列表。

1 import subprocess
2 
3 subprocess.run(
4     f"cat file | sh script1.sh | sh script2.sh | uniq  > output.txt",
5     check=True,
6     shell=True)

  特别说明,shell参数是官方不推荐使用的,有shell注入的风险。如果命令是由外部用户传入的(如ping -c 1 baidu.com; rm -rf *)就比较危险。如果是自用的那关系不大。

 

  例子5 通过当前进程给子进程传入数据

1 import subprocess
2 
3 p = subprocess.run(['grep', ''],
4                    input='one
two
three
吴'.encode("utf-8"),
5                    capture_output=True)
6 print(p.stdout.decode("utf-8"))
 1 import subprocess
 2 
 3 # 在file中提取身份证号码
 4 f = open("file", encoding='utf-8')
 5 p = subprocess.run(['grep', '-E', r'([1-9]d{5}(18|19|([23]d))d{2}((0[1-9])|('
 6                                   r'10|11|12))(([0-2][1-9])|10|20|30|31)d{3}['
 7                                   r'0-9Xx])|([1-9]d{5}d{2}((0[1-9])|('
 8                                   r'10|11|12))(([ '
 9                                   r'0-2][1-9])|10|20|30|31)d{2})'],
10                    stdin=f,
11                    capture_output=True)
12 print(p.stdout.decode("utf-8"))

   例子6 使用timeout选项设置超时时间

 1 import subprocess
 2 
 3 max_runs = 2
 4 run = 0
 5 while run < max_runs:
 6     try:
 7         subprocess.run(["sleep", "5"], timeout=3)
 8     except subprocess.TimeoutExpired:
 9         print("timeout")
10         continue
11     else:
12         break
13     finally:
14         run += 1

  进阶的使用方式Popen类

  

  例子1  子进程独立于父进程运行

1 import subprocess
2 
3 proc = subprocess.Popen(['ls', '-l'])
4 while proc.poll() is None:
5     print('Working')
6     print('Exit status', proc.poll()) # poll()检查子进程是否已被终止, 并设置返回码

 

  例子2 父进程等待子进程运行,并统计子进程的完成时间

 1 import time
 2 import subprocess
 3 
 4 start = time.time()
 5 sleep_procs = []
 6 for _ in range(10):
 7     proc = subprocess.Popen(['sleep', '1'])
 8     sleep_procs.append(proc)
 9 
10 for proc in sleep_procs:
11     proc.communicate()  # 等待子进程的执行
12 
13 end = time.time()
14 delta = end - start
15 print(f'Finished in {delta:.3} seconds')

   例子3 子进程之间通过管道连接起来

1 import subprocess
2 
3 proc_cat = subprocess.Popen(['cat', 'file'], stdout=subprocess.PIPE)
4 proc_grep = subprocess.Popen(['grep', ''], stdin=proc_cat.stdout)
5 proc_cat.stdout.close() # 下游的进程启动后,上游的进程的stdout需要及时关闭
6 proc_cat.stdout = None

 

  

 
 
 
 
 
原文地址:https://www.cnblogs.com/Bowu/p/14761720.html