Python调用os.popen控制台不输出stderr的方法

本文探讨如何在使用os.popen时避免命令的stderr输出到控制台。虽然常见解决方案是通过脚本和重定向,但作者推荐使用subprocess.Popen方法,通过设置stderr参数来捕获并控制错误输出。

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

声明:这是个标题党,如果你执意想用os.popen做到控制台输出重定向,这篇文章中并没有答案,如果你对os.popen没有那么强烈的执念,请继续看

前段时间写代码使用os.popen时,遇到一个问题:执行的命令有可能会运行失败,虽然在代码中增加了异常处理,但是对于功能的要求是,不能在控制台打印出来报错信息,附上使用os.popen的情况:

# -*- coding: utf-8 -*-
import os

if __name__ == '__main__':
    CMD = "adb -H 1.2.3.5 devices"  # ip未知,执行肯定会报错
    prco = os.popen(CMD, mode="r", buffering=-1)
    outputStr = str(prco.read())
    print("output: " + outputStr)

控制台输出结果是这样的:

** Cannot start server on remote host
error: can't connect to 1.2.3.5:7305: cannot connect to 1.2.3.5:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)
output: List of devices attached

可以看到前两行输出部署预期想要的,那要怎么才能不让命令中的stderr输出到控制台呢?网上搜了下,大把的解决方法都是写个脚本,让popen调用这个脚本,然后用输出重定向的方式去解决这个问题。但是!不!够!优!雅!

有没有一种方式可以直接过滤掉stderr呢?答案是肯定的,我们可以通过subprocess.Popen方法完美解决这个问题

# -*- coding: utf-8 -*-

import subprocess
import io

if __name__ == '__main__':
    
    CMD = "adb -H 1.2.3.5 devices"  # ip未知,执行肯定会报错
      
    proc = subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=-1)
    proc.wait()
    stream_stdout = io.TextIOWrapper(proc.stdout, encoding='utf-8')
    stream_stderr = io.TextIOWrapper(proc.stderr, encoding='utf-8')
      
    str_stdout = str(stream_stdout.read())
    str_stderr = str(stream_stderr.read())
      
    print("stdout: " + str_stdout)
    print("stderr: " + str_stderr)

控制台输出结果:

stdout: List of devices attached

stderr: ** Cannot start server on remote host
error: can't connect to 1.2.3.5:7305: cannot connect to 1.2.3.5:7305: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。 (10060)

这样就能捕捉并指定输出stderr的内容了,顺便说一句,这里也可以将Popen中的stderr参数值从subprocess.PIPE换成subprocess.DEVNULL,不过这样就不会得到stderr的输出了。

os.popen和subprocess.Popen在功能上都是对控制台进行读写操作的,其中的区别可参见我的另一篇文章:https://blog.youkuaiyun.com/Ls4034/article/details/89386857

Python中,如果你想要通过`subprocess.Popen`创建的子进程变成守护进程,你需要采取特殊的步骤来完成,因为`Popen`本身并直接提供将子进程设置为守护进程的功能。过,你可以通过以下方法间接实现: 1. ** fork() 和 exec() **:首先,你可以创建子进程(通常是通过`os.fork()`),然后在新的子进程中调用`os.setpgrp()`,将当前进程组设置为一个新的进程组。接着,在新进程组内再次调用`os.execve()`替换掉原来的进程,此时的进程将成为一个独立的、受原父进程控制的守护进程。 ```python import os def daemonize(): # 创建新进程组 if os.fork() > 0: # 父进程退出 os._exit(0) # 第二个子进程 os.setsid() # 再次创建新的进程,这次作为守护进程 if os.fork() > 0: os._exit(0) # 确保关闭所有文件描述符 for fd in range(3, os.sysconf('SC_OPEN_MAX')): try: os.close(fd) except Exception: pass # 启动你想执行的命令 cmd = ['your_command', 'arg1', 'arg2'] with open(os.devnull, 'w') as devnull: subprocess.Popen(cmd, stdin=devnull, stdout=devnull, stderr=devnull) ``` 2. **使用multiprocessing模块**:如果你正在使用`multiprocessing`模块,你可以利用`Process`对象的`daemon`属性,创建一个守护进程。但是请注意,这种方式只适用于`multiprocessing`模块内的子进程。 ```python from multiprocessing import Process def worker(): # 这里是你的工作代码... if __name__ == '__main__': p = Process(target=worker, daemon=True) # 将进程设为守护进程 p.start() ``` 这两种方法都需要注意,一旦子进程变成守护进程,它们将控制台的直接影响,而且可能在系统重启时被自动杀死,因此在实际应用中要谨慎使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值