python Popen使用

本文介绍了一个使用Python脚本从Redis数据库中读取特定内容签名对应数据的方法。该脚本通过命令行与一个名为DIRedisWriter2的进程交互,发送内容签名以获取相关数据,并处理返回结果。
#encoding:utf-8


#author:liudapeng
#description: read redis result according to contSign
#date:2015/01/19


import os
import sys
import json
import Queue
import threading
import subprocess
from subprocess import *
import inspect
import time


    
if __name__ == "__main__":
    shellCommand = '''cd {0} && ./DIRedisWriter 2>/dev/null'''.format('./')
    process = Popen(['/bin/bash', '-c', shellCommand], stdin=PIPE, stdout=PIPE, stderr = sys.stderr)
    for line in sys.stdin:
        try:
            contentSign = line.rstrip("\r\n")
            cmd = '''read\t101\t{0}\n'''.format(contentSign)
            process.stdin.write(cmd)
            while True:
                result = process.stdout.readline()
                result = result.strip("\r\n")
                if result == "end":
                    break
                else:
                    if result != "NORESULT":
                        print result
                    else: 
                        print "0"+"\t"+contentSign+"\t"+"NOURLMD5"
        except Exception,e:
            print e
            pass
    if process != None :
        process.kill()
        process = None 
<think>首先,用户的问题是关于Pythonpopen对象的readlines方法的使用详解。用户提到了“popen readlines”,所以我需要聚焦于Popen对象的readlines方法。 从系统指令中,我知道必须使用中文回答,结构清晰,帮助用户逐步解决问题。同时,需要生成相关问题,并确保回答真实可靠。 参考了站内引用: - 引用[1]:提到了Popen.communicate()来避免死锁问题,以及获取返回值。 - 引用[2]:关于Python-Scrapyd-API,但似乎不直接相关。 - 引用[3]:提到在*nix下,Popen使用os.execvp(),args应为列表。 用户意图是继续查询Popen的readlines方法,所以我需要基于这些引用构建回答。 关键点: - readlines方法是用于读取子进程的输出。 - 引用[1]警告了死锁问题,建议使用communicate()代替。 - readlines可能阻塞,如果输出很大,会导致问题。 回答结构: 1. **介绍Popen和readlines**:解释什么是Popen和readlines方法。 2. **使用方法**:展示如何使用readlines。 3. **注意事项**:讨论潜在问题,如死锁,并引用[1]的建议。 4. **示例代码**:提供一个简单的Python代码示例。 5. **最佳实践**:推荐使用communicate()以避免问题。 6. **生成相关问题**:在最后添加相关问题。 确保LaTeX格式正确:所有行内数学表达式用$...$,独立公式用$$...$$。但在这个上下文中,可能不需要数学公式,除非涉及计算。 现在,构建回答: - **标题**:Python popen readlines 方法使用详解 - **内容**: - 解释Popen:subprocess.Popen用于启动子进程。 - readlines方法:用于读取标准输出或错误的所有行。 - 死锁风险:如果输出缓冲区满,可能导致阻塞。引用[1]提到使用communicate()来避免。 - 示例:展示一个简单的代码片段。 - 建议:优先使用communicate()。 最后,生成相关问题: - 例如: 1. 如何避免Popen中的死锁问题? 2. Popen.communicate()和readlines()有什么区别? 3. 在Python中如何安全地读取子进程输出? 确保引用自然添加:在相关段落末尾添加引用标识。</think>### Python popen readlines 方法使用详解 在Python中,`subprocess.Popen` 是用于创建和管理子进程的核心模块,常用于执行外部命令或程序。`readlines()` 是文件对象的一个方法,用于读取所有行并返回一个列表。当与 `Popen` 结合使用时,它可以读取子进程的标准输出(stdout)或标准错误(stderr)。下面我将逐步解释其使用方法、注意事项和最佳实践,确保回答基于可靠参考。 #### 1. **基本概念** - `Popen` 对象:通过 `subprocess.Popen` 创建,代表一个子进程。它可以访问子进程的输入/输出流(如 stdout 和 stderr)。 - `readlines()` 方法:属于文件对象(如 `Popen.stdout`),用于读取所有输出行并返回一个字符串列表。每个元素对应一行输出(包括换行符)。 - 使用场景:适合处理输出量小的命令,例如读取命令的完整结果到内存中。 #### 2. **基本使用方法** 使用 `Popen` 创建子进程后,通过 `stdout.read()` 或 `stdout.readlines()` 读取输出。以下是一个简单示例: ```python import subprocess # 启动子进程,并捕获 stdout process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) # 使用 readlines() 读取所有输出行 output_lines = process.stdout.readlines() error_lines = process.stderr.readlines() # 打印结果 print("标准输出:") for line in output_lines: print(line.strip()) # 去除换行符 # 等待进程结束并获取返回码 return_code = process.wait() print(f"返回码: {return_code}") ``` - 关键参数: - `stdout=subprocess.PIPE`:将子进程的 stdout 重定向到管道,以便 Python 读取。 - `stderr=subprocess.PIPE`:类似地处理错误输出。 - `text=True`:确保输出为字符串(Python 3.5+),否则需手动解码二进制数据。 - `readlines()` 返回列表,例如 `['file1.txt\n', 'file2.txt\n']`。 #### 3. **注意事项和常见问题** - **死锁风险**:如果子进程的输出量过大(例如超过系统管道缓冲区),`readlines()` 可能阻塞,导致父进程和子进程相互等待(死锁)。这是因为管道缓冲区满时,子进程无法写入,父进程无法读取[^1]。 - 解决方案:优先使用 `Popen.communicate()` 方法,它自动处理缓冲,避免死锁,并一次性返回所有输出。例如: ```python process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) stdout_data, stderr_data = process.communicate() # 安全读取所有输出 ``` `communicate()` 将输出加载到内存,适合大输出场景,且能获取返回码(通过 `process.returncode`)[^1]。 - **参数格式**:`Popen` 的 `args` 参数应为列表(如 `['ls', '-l']`),而非字符串。如果使用字符串(如 `'ls -l'`),需设置 `shell=True`,但这可能引入安全风险(命令注入)[^3]。 - **资源管理**:读取后必须关闭流或使用 `process.wait()` 等待进程结束,避免僵尸进程。 - **性能问题**:`readlines()` 一次性加载所有输出到内存,不适合处理超大输出(如 GB 级文件)。此时应使用迭代读取: ```python for line in process.stdout: # 逐行迭代,减少内存占用 print(line.strip()) ``` #### 4. **最佳实践** - **优先使用 `communicate()`**:对于大多数场景,`communicate()` 更安全高效,尤其避免死锁[^1]。 - **错误处理**:检查 `stderr` 和返回码: ```python if process.returncode != 0: print(f"错误: {stderr_data}") ``` - **编码处理**:如果输出为二进制,需手动解码: ```python process = subprocess.Popen(['command'], stdout=subprocess.PIPE) output = [line.decode('utf-8') for line in process.stdout.readlines()] ``` - **超时控制**:使用 `timeout` 参数(Python 3.3+)防止进程挂起: ```python try: stdout_data, stderr_data = process.communicate(timeout=10) except subprocess.TimeoutExpired: process.kill() ``` #### 5. **示例:完整流程** 以下代码展示了安全读取命令输出的完整流程: ```python import subprocess def run_command(command): try: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) stdout, stderr = process.communicate(timeout=30) # 使用 communicate 避免死锁 if process.returncode == 0: print("输出成功:") print(stdout) else: print(f"命令失败,返回码: {process.returncode}") print(f"错误信息: {stderr}") except subprocess.TimeoutExpired: process.kill() print("命令超时,已终止") except Exception as e: print(f"发生异常: {e}") # 测试命令 run_command(['ls', '-l']) ``` #### 总结 `Popen` 的 `readlines()` 方法简单易用,但存在死锁风险,特别是在处理大量输出时。推荐使用 `communicate()` 作为更安全的替代方案[^1]。在实际应用中,始终考虑输出大小、错误处理和超时控制,以确保代码健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值