zoukankan      html  css  js  c++  java
  • 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

     

      

     
     
     
     
     
  • 相关阅读:
    phonegap helloworld 之android
    perl 信号
    css的浮动
    css的定位
    p4 环境变量的优先级
    oracle sql 高级
    perl数组高级
    让你提升命令行效率的 Bash 快捷键 [完整版]
    函数的返回值为结构体类型
    函数的返回值保存在内存的什么区域
  • 原文地址:https://www.cnblogs.com/Bowu/p/14761720.html
Copyright © 2011-2022 走看看