如何隐藏子进程的输出

10 浏览
0 Comments

如何隐藏子进程的输出

我在Ubuntu上使用eSpeak,并有一个Python 2.7脚本用于打印和朗读一条消息:

import subprocess
text = '你好,世界。'
print text
subprocess.call(['espeak', text])

eSpeak能够产生所需的声音,但是在终端上会有一些错误信息(ALSA lib...,无法连接到socket),所以我无法轻松地阅读之前打印的内容。退出代码为0。

不幸的是,没有记录的选项可以关闭其冗长的输出,所以我正在寻找一种方式只是视觉上将其静音,并保持终端干净以便进行进一步的交互。

我该如何做到这一点?

0
0 Comments

如何隐藏子进程的输出

在Python 3.3及以上版本中,将输出重定向到DEVNULL:

import os
import subprocess
retcode = subprocess.call(['echo', 'foo'], 
    stdout=subprocess.DEVNULL,
    stderr=subprocess.STDOUT)

在Python 3.3以下的版本中,包括2.7版本,可以使用以下代码:

FNULL = open(os.devnull, 'w')
retcode = subprocess.call(['echo', 'foo'], 
    stdout=FNULL, 
    stderr=subprocess.STDOUT)

这实际上与运行以下shell命令相同:

retcode = os.system("echo 'foo' &> /dev/null")

一些小技巧:如果subprocess.DEVNULL不可用(<3.3),可以使用os.devnull,如果你不检查返回的代码,可以使用check_call()代替call(),对于stdin/stdout/stderr,以二进制模式打开文件,应该避免使用os.system(),在Ubuntu上, >不适用于sh,可以明确使用>/dev/null 2>&1。

F.Sebastian: 感谢您的建议。我实际上想使用os.devnull,但是不小心拼错了。另外,我使用了OPs的call方法,因为他们没有捕获check_call可能引发的异常。对于os.system的重定向,更多只是说明了subprocess方法的有效用法,而不是作为第二个建议。

你不需要关闭你打开的FNULL吗?

只是一个提示,你可以在subprocess.call中使用close_fds=True,在子进程退出后关闭FNULL描述符。

我以为close_fds是为了在fork的进程中关闭继承的文件描述符,而不是在父进程这边关闭任何东西。

你不能只是在你的代码中放一个try块,在finally块中做:FNULL.close()吗?这样它无论如何都会关闭。

你可能是对的。我阅读了模块的代码,看起来是这样的,但是文档确实指定它关闭子进程的描述符。

没错。它在子进程中关闭文件描述符,以防止它继承除stdin、stdout、stderr之外的所有父进程描述符。我不是真的明白为什么会有一个关于如何关闭文件句柄的对话。事实上,我只是写了关于调用子进程的那一行代码是为了简洁。是的,显然你需要关闭你打开的任何文件句柄。我只是没有认为我需要写一个更广泛的例子。你可以手动关闭它,或者使用try/finally,或者使用with-context。

关于close_fds=True,文件描述符在fork()之后但在execvp()之前关闭,也就是在可执行文件运行之前,在子进程中关闭。close_fds在Windows上无法工作,如果任何流被重定向。close_fds不会关闭父进程中的文件。

这里有一个类似的答案,除了内联和字节模式:stackoverflow.com/a/8529412/1695680

对于Python 3来说是个很棒的答案!

看起来并不总是可行。在Python 2.7(Windows 7)上与7zip一起使用时,如果将stderr更改为FNULL(或stdout=FNULL,stderr=subprocess.STDOUT),子进程(7zip)会立即失败。(可能是7zip特定的问题)

它绝对是一个适用于大多数情况的解决方案。我无法确认在Windows + 7zip上的具体情况。我不熟悉Windows + 7zip可能引入的任何怪异问题。

这是一种旧的和原始的运行命令的方式,它对子进程的控制很少。subprocess模块统一了所有这些较旧的风格。例如,你不能得到pid并在需要时终止进程。你不能获取输出,并且控制输出流或环境的唯一方法是在命令格式化中。

在subprocess.check_output()下是否可以调用它?

当然可以。它们只是基本上相同的东西的包装器,具有不同的默认选项。check_output默认将stdout捕获到一个管道中并返回数据,这与将其管道连接到devnull以丢弃它稍有不同。你仍然可能希望根据需要设置stderr。

0
0 Comments

问题的出现原因:在使用subprocess模块的Popen函数执行子进程时,有时候需要隐藏子进程的输出,但是默认情况下,子进程的输出会被打印到终端上。因此,需要找到方法来隐藏子进程的输出。

解决方法:上述代码提供了一种解决方法,即使用stdout参数将子进程的输出重定向到特殊的文件描述符DEVNULL,从而隐藏输出。具体步骤如下:

1. 导入所需的模块:from subprocess import Popen, PIPE, STDOUT

2. 判断当前Python版本,并根据版本导入相应的模块或打开文件描述符:

- 如果是Python 3,则导入subprocess模块的DEVNULL:from subprocess import DEVNULL

- 如果是Python 2,则通过os模块打开系统的null设备文件描述符:DEVNULL = open(os.devnull, 'wb')

3. 定义要执行的子进程命令和输入内容:text = u"René Descartes"

4. 使用Popen函数创建子进程对象,并指定输入、输出和错误流的重定向:

- stdin参数指定子进程的输入流,这里使用PIPE表示通过管道输入

- stdout参数指定子进程的输出流,这里使用DEVNULL表示重定向到特殊的文件描述符

- stderr参数指定子进程的错误流,这里使用STDOUT表示将错误流与输出流合并

5. 调用communicate方法向子进程发送输入内容,并等待子进程执行完毕

6. 使用assert语句检查子进程的返回码,根据实际需要进行适当的错误处理

需要注意的是,上述代码中使用的DEVNULL并不是完全通用的,它只能用于重定向输出流,无法用于重定向输入流。如果需要重定向输入流,可以使用'r+b'模式替代'wb'模式。

此外,文章还提到了一种更简洁的解决方法:直接使用subprocess模块的DEVNULL常量作为stdout参数,即stdout=subprocess.DEVNULL。这种方法适用于Python 3,并且代码更加简洁。

最后,文章还提到了代码的兼容性:如果不需要支持Python 2,只需导入subprocess模块的DEVNULL即可。

0
0 Comments

使用subprocess.check_output可以隐藏子进程的输出。它是Python 2.7中新增的功能,它会抑制stdout并在命令失败时引发异常。(实际上,它会返回stdout的内容,因此您可以在程序的其他位置使用它,如果需要的话。)示例代码如下:

import subprocess
try:
    subprocess.check_output(['espeak', text])
except subprocess.CalledProcessError:
    # Do something

您还可以使用以下代码来抑制stderr:

subprocess.check_output(["espeak", text], stderr=subprocess.STDOUT)

对于早于2.7的版本,可以使用以下代码:

import os
import subprocess
with open(os.devnull, 'w')  as FNULL:
    try:
        subprocess._check_call(['espeak', text], stdout=FNULL)
    except subprocess.CalledProcessError:
        # Do something

在这里,您可以使用以下代码来抑制stderr:

subprocess._check_call(['espeak', text], stdout=FNULL, stderr=FNULL)

更准确地说,它返回stdout的内容。这非常好,因为您可能希望在忽略它之外还使用它。

我认为这更直观。我认为您应该使用CalledProcessError来处理错误,例如except subprocess.CalledProcessError as e,然后使用e.codee.output

对于使用变量和与REST服务进行通信的更复杂的shell命令,这非常有用(在我这种情况下,subprocess.run无法正常工作)。

0