/usr/bin/which 作为 python 子进程调用时有奇怪的行为
/usr/bin/which has strange behavior when called as python subprocess
我有一个 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
,那么它有 return 代码 0,否则它有 return 代码 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 子进程将标准输出重定向到 /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
表现得像这样?
您正在以默认模式(即 'r'
[阅读])打开 "file" (/dev/null)。但是,subprocess
正在尝试 将 写入文件——因此您可能想要:
with open(os.devnull, 'w') as nil:
p = subprocess.call(['which', 'program'], stdout=nil, stderr=nil)
我有一个 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
,那么它有 return 代码 0,否则它有 return 代码 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 子进程将标准输出重定向到 /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
表现得像这样?
您正在以默认模式(即 'r'
[阅读])打开 "file" (/dev/null)。但是,subprocess
正在尝试 将 写入文件——因此您可能想要:
with open(os.devnull, 'w') as nil:
p = subprocess.call(['which', 'program'], stdout=nil, stderr=nil)