Python subprocess.Popen 实时输出 stdout(正确管道写法)

本文探讨了在使用Python subprocess模块时,如何解决子进程输出被缓存的问题,提供了一种实时读取子进程输出的方法,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大部分的程序是这样的:

from subprocess import Popen, PIPE, STDOUT

p = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True)
while True:
    print(p.stdout.readline())
    if not line: 
        break

但是由于子程序没有进行 flush 的话,会把结果缓存到系统中。导致程序运行完成,上面的程序才会进行打出(会一直卡在readline这个函数)。

解决方法:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1)
for line in iter(p.stdout.readline, b''):
    print line,
p.stdout.close()
p.wait()

实际弱口令我是这样写的

import subprocess     #Popen


proc = subprocess.Popen(medusaCMD, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
for line in iter(proc.stdout.readline, 'b'):
    print line
    if not subprocess.Popen.poll(proc) is None:
        if line == "":
            break
proc.stdout.close()

记小的写法

proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
try:
    while True:
        buff = proc.stdout.readline()
        print(buff)
        if buff == '' and proc.poll() != None:
            break
        else:
            .....
except Exception:
    data["status"] = -1
finally:
    return data

单次管道输出写法

方法一

# -*- coding: UTF-8 -*-

import re
import sys
import subprocess
from subprocess import Popen, PIPE, STDOUT

#docker_info = {"CONTAINER ID":"", "NAME":"", "CPU %":"", "MEM USAGE / LIMIT":"", \
#               "MEM %":"", "NET I/O":"", "BLOCK I/O":"", "PIDS":""}
docker_list = []


cmd = "docker stats -a --no-stream"
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
try:
    buff = proc.communicate()
    stritem = buff[0]
    str_list = re.split(r'  +|\n', stritem)
    for i in range(8, len(str_list)-1):
        if i % 8 == 0:
            value = 0
            docker_info = {}
            docker_info["CONTAINER ID"] = str_list[i]
        else:
            value += 1
            if value == 1:
                docker_info["NAME"] = str_list[i]
            elif value == 2:
                docker_info["CPU %"] = str_list[i]
            elif value == 3:
                docker_info["MEM USAGE / LIMIT"] = str_list[i]
            elif value == 4:
                docker_info["MEM %"] = str_list[i]
            elif value == 5:
                docker_info["NET I/O"] = str_list[i]
            elif value == 6:
                docker_info["BLOCK I/O"] = str_list[i]
            elif value == 7:
                docker_info["PIDS"] = str_list[i]
                docker_list.append(docker_info)
                value = 0
    print docker_list
except Exception as e:
    print "error", e
    sys.exit(1)
    proc.stdout.close()

方法二(待测试)

import subprocess
from multiprocessing.dummy import Pool as ThreadPool

command = poc + ' -t ' + ip + ' -p ' + port
result = subprocess.getoutput(command)
if 'WARNING: SERVER IS VULNERABLE' in result:
    result = AAAAA
else:
    result = BBBBBB

 

<think>嗯,用户想了解如何使用subprocess.run来执行nohup ./nps &这样的后台命令。首先,我得回忆一下subprocess模块的基本用法,尤其是subprocess.run的参数设置。记得subprocess.run默认会等待子进程结束,所以如果直接执行带有&的shell命令,可能需要使用shell=True参数。不过,使用shell=True可能会有安全风险,如果用户输入不可信的话需要提醒。 然后,nohup的作用是忽略SIGHUP信号,让进程在终端关闭后继续运行。而&是将进程放到后台执行。这两个组合起来通常用于启动后台服务。但问题在于,当通过subprocess.run执行时,即使加上&,父进程(也就是Python脚本)可能会等待子进程结束,因为shell可能会立即返回,但实际进程可能还在运行。这时候可能需要处理标准输入输出,因为nohup默认会输出到nohup.out,或者需要重定向。 接下来考虑具体的代码实现。用户可能想用类似subprocess.run(["nohup", "./nps", "&"])的方式,但这样不行,因为&是shell的操作符,不是命令参数。所以必须通过shell=True来执行整个命令字符串。正确写法应该是subprocess.run("nohup ./nps &", shell=True, check=True)。不过,这里可能需要处理输入输出,比如关闭stdin、stdout、stderr,或者重定向到文件,否则subprocess可能会因为管道问题而挂起。 另外,使用shell=True时,要注意命令注入的风险。如果./nps的路径或参数是用户可控的,可能会有安全问题。但用户这里的情况是固定的命令,所以问题不大,不过还是应该提醒这一点。 还需要注意subprocess.run的选项,比如detach进程。可能需要设置start_new_session参数,类似于nohup的效果,但这里已经用了nohup,所以可能不需要。不过,有时候双重保障可能更好,但需要测试。 还有,当使用shell=True时,子进程的PID可能不是nps的PID,而是shell的PID,所以如果需要获取子进程的PID,可能需要使用其他方法,比如pgrep,但用户的问题可能不需要这个。 总结步骤应该是:使用shell=True执行整个命令字符串,处理输入输出重定向,确保进程正确后台运行,并且Python脚本不会等待。同时,提醒安全注意事项和可能需要的错误处理。</think>在Python中使用`subprocess.run`执行`nohup ./nps &`这类后台命令时,需注意以下关键点: --- ### 1. 直接执行的问题 ```python subprocess.run("nohup ./nps &", shell=True) ``` - **表面可行但存在隐患**:虽然能启动后台进程,但`subprocess.run`默认会等待子进程结束。若`nps`进程未完全脱离,可能导致Python脚本阻塞 --- ### 2. 推荐解决方案 ```python subprocess.run( "nohup ./nps >/dev/null 2>&1 &", shell=True, check=True, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL ) ``` - **关键参数说明**: - `>/dev/null 2>&1`:重定向输出,防止nohup生成默认的`nohup.out` - `stdin/stdout/stderr=subprocess.DEVNULL`:关闭文件描述符,避免父进程挂起 - `check=True`:检查命令执行是否成功 --- ### 3. 更安全的替代方案(推荐) ```python with open(os.devnull, 'w') as devnull: subprocess.Popen( ["./nps"], stdout=devnull, stderr=devnull, stdin=devnull, start_new_session=True # 替代nohup的作用 ) ``` - **优势**: - 避免使用`shell=True`,降低安全风险 - `start_new_session=True`等效于`nohup`的防SIGHUP功能 - 更规范的输入输出处理 --- ### 4. 注意事项 1. **安全警告**: - `shell=True`存在命令注入风险,若参数含用户输入内容需严格过滤 - 推荐优先使用`Popen`+参数列表方式 2. **环境依赖**: - 确保执行目录正确(可通过`cwd`参数指定工作目录) - 注意环境变量继承问题,必要时使用`env`参数 3. **日志管理**: ```python with open("nps.log", "w") as logfile: subprocess.Popen(... , stdout=logfile, stderr=subprocess.STDOUT) ``` 可自定义日志输出位置 --- ### 5. 验证进程状态 执行后可通过以下命令验证: ```bash ps aux | grep nps # 查看进程是否存在 lsof -p <PID> # 检查文件描述符是否正常关闭 ``` 通过以上方法,即可安全可靠地实现后台进程的启动与管理。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

墨痕诉清风

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值