对带有 2>/dev/null 的命令使用 subprocess.check_output

Posted

技术标签:

【中文标题】对带有 2>/dev/null 的命令使用 subprocess.check_output【英文标题】:Using subprocess.check_output for a command with 2>/dev/null 【发布时间】:2015-09-03 00:05:36 【问题描述】:

我使用的是 Mac OS X Yosemite 10.10 和 Python 2.7。

如果我在命令行中键入以下内容:du -g -d1 /Users 2> /dev/null,则一切正常。

现在,我的目标是在 python 脚本中使用该命令。

我的想法是使用以下内容:

import subprocess

output = subprocess.check_output(['du', '-g', '-d1', '/Users', '/dev/null'])

但我得到这个错误:

Traceback (most recent call last):
  File "./verifications.py", line 1, in <module>
    output = subprocess.check_output(['du', '-g', '-d1', '/Users', '/dev/null'])
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 537, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['du', '-g', '-d1', '/Users', '/dev/null']' returned non-zero exit status 1

此外,当我在本地运行 subprocess.check_output(['du', '-g', '-d1', '/Users', '/dev/null']) 时一切正常,当我使用 Apple 的共享屏幕工具登录共享 iMac 时会发生错误。我感觉问题可能出在权限上,但我找不到任何东西。

【问题讨论】:

&gt;/dev/null 是重定向,而不是参数。也就是说,它在运行命令之前告诉shell如何为命令设置文件描述符,而实际上根本没有传递给du命令。 ...哦——在你的问题前面你使用2&gt;/dev/null。这意味着不同的东西。请尽量保持一致。 但这仍然是docs.python.org/3.1/library/subprocess.html 使用它的方式。 该文档正在传递文字参数,而不是执行重定向。也就是说,它运行的是ls -l /dev/null,而不是ls -l &gt;/dev/nullls -l 2&gt;/dev/null。这三个是完全不同的命令。 哦,所以我想我有点混淆了。 【参考方案1】:

对于2&gt;/dev/null,使用subprocess.Popen 系列调用控制文件描述符2 重定向的适当方法是stderr=

# Python 2.x, or 3.0-3.2
output = subprocess.check_output(['du', '-g', '-d1', '/Users'],
                                 stderr=open('/dev/null', 'w'))

...或者,使用支持subprocess.DEVNULL的Python:

# Python 3.3 or newer
output = subprocess.check_output(['du', '-g', '-d1', '/Users'], stderr=subprocess.DEVNULL)

顺便说一句,就个人而言,我建议更像这样:

p = subprocess.Popen(['du', '-g', '-d1', '/Users'],
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
  raise Exception(stderr)

...不是将stderr 发送到/dev/null,而是保留它以在命令失败时生成有用的异常。 (显然,选择一个适当的 Exception 子类)。

【讨论】:

不确定我是否理解正确,但这就是我现在得到的:>>> import subprocess >>> output = subprocess.check_output(['du', '-g', '-d1 ', '/Users'], stdout=open('/dev/null', 'w')) Traceback(最近一次调用最后):文件“”,第 1 行,在 文件“/System /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py",第 529 行,在 check_output 中引发 ValueError('stdout 参数不允许,它将被覆盖。') ValueError:stdout 参数不是允许,它将被覆盖。 重新阅读答案(如果您的浏览器没有跟上编辑,请重新加载)。你会注意到我使用的是stderr=,而不是stdout=。 stdout 是 FD 1 - 这是 &gt;/dev/null 重定向的内容,正如我在完全删除该部分之前所说的那样,重定向对于 check_output() 没有意义。 假设我们忘记了我的想法。你将如何在 python 脚本中执行 du -g -d1 /Users 2> /dev/null ? /edit 我需要捕获结果,以便稍后在脚本中使用它。 就个人而言,我会收集 stdout 和 stderr —— 丢弃错误消息而不是记录它们以在异常中使用是愚蠢的。这样做,可以使用communicate() 调用。 如果您想要准确的总大小为/Users及其所有子目录,则需要 +rx 来其所有子目录。无法解决这个问题。如果您拥有的所有+rx 权限是/Users,那么您只能在/Users 本身中获取文件的大小,这不是很有帮助。无论如何,这现在完全是题外话了。关于您需要使用哪些权限du 的问题应单独询问(可能在superuser.com 或unix.stackexchange.com 上)。如果您想忽略错误并接受不准确的结果,请做明显的事情并取出raise Exception

以上是关于对带有 2>/dev/null 的命令使用 subprocess.check_output的主要内容,如果未能解决你的问题,请参考以下文章

;/dev/null 2;&1 和 2;&1 ;/dev/null 的区别

linux中 /dev/null命令

>/dev/null 2>&1 这句话的含义及使用的意义

关于linux中 command ; /dev/null 的详解

nohup /dev/null 2>&1 含义详解

/dev/null 位桶