【发布时间】:2015-02-10 21:22:13
【问题描述】:
我有一个 python (2.7) 包,它依赖于一个用 C 编写的库(大脑成像套件 Freesurfer)。为了检查图书馆,我写了以下内容:
def crash_if_freesurfer_not_found():
import os, subprocess
with open(os.devnull) as devnull:
p = subprocess.call(['which', 'mri_info'], stdout=devnull, stderr=devnull)
if p!=0:
print 'Useful error message'
sys.exit(1)
如果 which 在路径中找到程序 mri_info,则返回代码为 0,否则返回代码为 1。在我开发此程序的系统上,此方法有效。
我现在在一个系统上,这个代码失败了。但我很困惑为什么,因为 `os.environ['PATH'] 包含 ~/freesurfer/bin,这个程序所在的位置。
In [3]: os.environ['PATH'].split(':')[0]
Out[3]: '/home/aestrivex/freesurfer/freesurfer/bin'
In [11]: ls /home/aestrivex/freesurfer/freesurfer/bin | grep mri_info
mri_info*
于是我深入挖掘,发现了这种我不理解的奇怪行为:
In [10]: with open(os.devnull) as nil:
p = subprocess.call(['which', 'mri_info'], stdout=nil, stderr=nil)
....:
In [11]: p
Out[11]: 1
In [12]: with open(os.devnull) as nil:
p = subprocess.call(['which', 'mri_info'], stdout=nil)
....:
sh: printf: I/O error
In [13]: with open(os.devnull) as nil:
p = subprocess.call(['which', 'mri_info'])
....:
/home/aestrivex/freesurfer/freesurfer/bin/mri_info
aestrivex@apocrypha ~/gselu $ which which
/usr/bin/which
因此,每当 python 子进程将 stdout 重定向到 /dev/null 时,which 就会失败并出现 I/O 错误,否则会正常运行。
但我从 which 得到完全正常的行为,而不是在 python 子进程中
aestrivex@apocrypha ~/gselu $ which mri_info
/home/aestrivex/freesurfer/freesurfer/bin/mri_info
aestrivex@apocrypha ~/gselu $ which mri_info > /dev/null
aestrivex@apocrypha ~/gselu $ echo $?
0
我有几种方法可以修复此检查,但我的问题是,什么可能的上下文会导致此错误在 python 子进程中看到 which 的行为?
【问题讨论】:
-
你能从 python 执行其他命令并将其输出写入通过
open(os.devnull)打开的文件吗?此外,由于您以默认模式 ('r') 打开该“文件”,因此期待写入该“文件”的任何内容似乎很奇怪——如果您为'w'打开它会发生什么? -
谢谢,它适用于
'w'传递给打开。我应该抓住它,但我对为什么它在其他一些机器上没有附加标志的情况下工作感到困惑。我猜想在某些 shell 环境中检测到你试图写入 /dev/null 的地方有一些魔法,但没有,但在这种情况下,无论出于何种原因,它实际上写入了 /dev/null。 -
在处理伪文件时,谁知道操作系统实际执行了哪些检查?我会发布作为答案。
-
嘿,这意味着,我的回答在技术上也是正确的,但它错过了准确的点。
标签: python python-2.7 path subprocess