python基础subprocess使用场景、主要功能、高级用法;创建新进程、连接到其输入/输出/错误管道并获取其返回代码

一、背景

Python 中的模块subprocess允许您创建新进程、连接到其输入/输出/错误管道并获取其返回代码。它是一个功能强大的模块,可用于在 Python 代码中运行和管理子进程。
应用场景:

  1. 调用操作系统的命令,或者与其他进程进行交互

  2. 处理系统任务,执行外部程序,捕获命令输出,甚至进行错误处理和超时控制

  3. 本人博客 如何用python 执行一些linux 命令同时得到返回值的三种方法

    subprocess.run()      适用于简单的命令执行
    subprocess.call()     用于执行命令并返回退出码
    subprocess.Popen()    适合需要更精细控制的高级用法
    

二、主要功能

2.1 subprocess.run()

启用一个进程并等待其完成,执行指定的命令,并返回执行的结果。

  • 运行简单的命令 使用subprocess.run()
    capture_output=True 捕捉命令输出结果 stdout和错误stderr
    text=True 输出结果以字符串形式返回,不是字节流
    import subprocess
    
    result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
    print(output.returncode) # 0 成功
    print("stdout:", result.stdout) # 输出结果
    print("stderr:", result.stderr) # 输出错误信息
    
  • returncode 通过检查结果的属性来检查命令是否成功;
    check=True来启用错误检查
    import subprocess
    
    try:
        result = subprocess.run(['ls', '-l', '/nonexistent'], capture_output=True, text=True, check=True)
    except subprocess.CalledProcessError as e:
        print("Command failed with return code", e.returncode)
        print("stderr:", e.stderr)
    
  • 运行 Shell 命令:可以使用shell=True。请谨慎使用此选项,因为它可能导致 shell 注入等安全风险
    import subprocess
    
    result = subprocess.run('echo $HOME', shell=True, capture_output=True, text=True)
    print("stdout:", result.stdout)
    
  • 设置超时
    import subprocess
    
    try:
        # 设置命令超时时间为5秒
        result = subprocess.run(["sleep", "10"], capture_output=True, text=True, timeout=5)
    except subprocess.TimeoutExpired as e:
        print(f"Command timed out: {e}")
    
2.2 subprocess.Popen

如果你需要更复杂的控制,比如与进程进行实时通信或处理输入输出流,Popen()方法是最强大的选择。
通过它,你可以精确地控制子进程的启动和管理
Popen()返回一个进程对象,你可以通过它进行更多控制,例如获取输出、错误信息,或者向子进程发送输入

  • import subprocess
    process = subprocess.Popen(['ping', 'google.com'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    print('输出:', stdout.decode())
    print('错误:', stderr.decode())
    
  • import subprocess
    # 启动一个子进程并与它交互
    process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    # 读取输出和错误
    stdout, stderr = process.communicate()
    print("stdout:", stdout)
    print("stderr:", stderr)
    
2.3 subprocess.call

call()方法会执行命令,但不会返回进程的详细信息。
如果你仅仅需要执行一个命令并检查它是否成功,call()就非常合适。
return_code会返回命令执行的退出码。如果命令成功执行,通常返回0

  • import subprocess
    # 执行一个系统命令并返回状态码
    return_code = subprocess.call(['ls', '-l'])
    
    print('命令执行完成,状态码:', return_code)
    这里,return_code会返回命令执行的退出码。如果命令成功执行,通常返回0

三、高级用法

  • 3.1 运行带有管道的命令
    如果你需要执行多个命令,并希望将它们的输出通过管道连接起来,subprocess也能轻松处理。以下是一个例子,先列出当前目录的文件,再将结果通过grep命令过滤:
    在这个示例中,p1命令列出了文件,而p2则通过管道过滤出了所有的.py文件。

    import subprocess
    
    # 第一个命令
    p1 = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
    
    # 第二个命令,通过管道传输数据
    p2 = subprocess.Popen(['grep', '.py'], stdin=p1.stdout, stdout=subprocess.PIPE)
    
    # 获取最终输出
    output = p2.communicate()[0]
    
    print('Python文件列表:')
    print(output.decode())
    
  • 与子进程交互:提供输入和获取输出

    import subprocess
    process = subprocess.Popen(['grep', 'hello'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
    stdout, stderr = process.communicate(input='hello world\n')
    print("stdout:", stdout)
    
    使用subprocess.Popen启动一个子进程,执行grep命令
    stdin=subprocess.PIPE表示我们可以向子进程提交输入数据
    stdout=subprocess.PIPE表示我们可以从子进程接收数据输出
    使用process.communicate()方法提交输入并获取输出
    

    subprocess 可以处理进程间的标准输入输出流,允许你向外部进程发送数据,并获取其输出。这对于需要与子进程进行交互的情况非常有用
    在这个例子中,我们通过input='Hello from Python!' 将输入传递给子进程,并从子进程获取输出

    result = subprocess.run(
        ['python3', '-c', 'import sys; print(sys.stdin.read())'],
        input='Hello from Python!',
        capture_output=True,
        text=True
    )
    
    print(result.stdout)  # 输出 "Hello from Python!"
    
  • subprocess还能做实时输出流处理:

    process = subprocess.Popen(['ping', 'python.org'], stdout=subprocess.PIPE, universal_newlines=True)
    while True:
        output = process.stdout.readline()
        if output == '' and process.poll() is not None:
            break
        if output:
            print(output.strip())
    
  • 如果你需要更细粒度的控制,创建一个进程并实时获取输出

    from subprocess import Popen, PIPE
    
    # 创建一个进程并实时获取输出
    with Popen(['ping', 'google.com'], stdout=PIPE, text=True) as proc:
        while True:
            line = proc.stdout.readline()
            if not line:
                break
            print(line, end='')
    
  • 备份数据库

    subprocess.run(['mysqldump', '-u', 'root', '-p', 'mydb', '>', 'backup.sql'], shell=True)
    
  • subprocess 可以用于系统监控,检查系统状态或资源使用情况

    # 检查CPU使用率
    result = subprocess.run(['top', '-bn1'], capture_output=True, text=True)
    print(result.stdout)
    
### 使用 `subprocess.Popen` 创建子进程 `subprocess.Popen` 是 Python 中用于创建子进程与其交互的核心类。它提供了灵活的方式执行外部命令与它们的标准输入、标准输出和标准错误流进行通信。 以下是关于 `subprocess.Popen` 的详细介绍以及示例代码: #### 基本语法 `subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)`[^1] - **args**: 要执行的命令及其参数,可以是字符串(当 `shell=True` 时),也可以是列表。 - **bufsize**: 缓冲区大小,默认为 0 表示未缓冲。 - **stdin**, **stdout**, **stderr**: 子进程的标准输入输出错误流,可设置为 `PIPE`, `DEVNULL`, 文件描述符或文件对象。 - **cwd**: 设置子进程的工作目录。 - **env**: 自定义环境变量字典。 - **shell**: 如果设为 True,则通过壳层执行命令;否则直接调用程序。 --- #### 示例代码 ##### 示例 1: 执行简单命令输出捕获到管道中 以下代码展示了如何使用 `subprocess.Popen` 来运行一个简单的命令,获取其标准输出: ```python import subprocess proc = subprocess.Popen( ["echo", "hello world"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) output, error = proc.communicate() print(output.decode('utf-8')) ``` 此代码片段中的 `communicate()` 方法等待子进程结束返回 `(stdout_data, stderr_data)`。 --- ##### 示例 2: 将输出重定向到文件 如果希望将子进程的输出保存到文件而不是内存中,可以通过如下方法实现: ```python with open("output.txt", "w") as f: proc = subprocess.Popen( ["ls", "-l"], stdout=f, stderr=subprocess.STDOUT ) proc.wait() ``` 在此示例中,`wait()` 方法被用来阻塞父进程直到子进程完成[^2]。 --- ##### 示例 3: 启动长时间运行的任务 对于某些可能不会立即退出的长期任务,比如监听用户输入的服务端脚本,可以这样处理: ```python proc = subprocess.Popen( ['bash', '-c', 'while true; do read -p "Enter something: "; done'], shell=True ) try: while True: line = input("Send to process (or type exit): ") if line.lower() == "exit": break proc.stdin.write(f"{line}\n".encode()) proc.stdin.flush() except KeyboardInterrupt: print("\nStopping...") finally: proc.terminate() ``` 上述代码模拟了一个持续接收输入的情况,允许手动终止该过程[^3]。 --- ### 注意事项 - 当 `shell=True` 参数启用时,命令应作为单个字符串提供给 args 参数。然而,在大多数情况下推荐避免使用 `shell=True`,因为它存在安全风险特别是拼接未经验证的用户数据时。 - 对于更复杂的场景考虑采用高级接口如 `subprocess.run()` 或者异步版本支持库 asyncio 提供的功能替代基础级 Popen 类操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风华浪浪

讨个老婆本呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值