在 Python Notebook 中调用 `subprocess` 的 `$PATH` 与 `!` shell 不同

问题描述 投票:0回答:1

我正在 IPython 笔记本中交互式开发一个包装类。 该包装类调用用 java 编写的命令行程序,因此我需要访问用于编译该程序的同一版本的 java 运行时。

但是,我注意到在笔记本中使用方便的

!
运算符,会生成与在终端中使用
zsh
时不同的 shell 实例。 这已得到证实:

!which java  # from within notebook cell
'/usr/bin/java' 

$ which java # on my zsh terminal
/opt/homebrew/opt/openjdk@11/bin/java 

运行

echo $PATH
也为每个人产生了不同的路径。

然后我遇到了 this StackOverflow 帖子,其中解释了

!
生成的子 shell 不会加载我的
.zshrc
文件(其中包含对在终端上使用
$PATH
时运行的
zsh
的修改) )。 但是,
!
子shell加载
.zshenv
文件(如果存在),我已成功将其创建为符号链接:

ln -s ~/.zshrc ~/.zshenv

运行此命令后,

!
现在有效地使用与我在终端上使用的相同的
zsh
,并且命令按预期工作,
!which java
产生正确的结果:
'/opt/homebrew/opt/openjdk@11/bin/java'

但是,我使用

!
作为测试和调试 shell 命令的便捷方法;但最终,我将这些 shell 命令调用移动到一个单独的
.py
文件中,我在其中使用
subprocess
模块。

当我使用

python3 script.py
从终端运行脚本时,一切都按预期运行;但是当将函数从
script.py
导入笔记本时,会产生与之前相同的问题。

作为一个最小的例子,来自笔记本:

!which java 
/opt/homebrew/opt/openjdk@11/bin/java 

这是正确的道路。 然而,

import subprocess
process = subprocess.run("which java", shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode("utf-8").strip()
output

给我:

'/usr/bin/java'

为什么

!
生成的 shell 能够访问我系统上与终端相同的
zsh
,但
subprocess
生成的 shell 却无法访问?

python shell subprocess ipython zsh
1个回答
0
投票

当您将

subprocess.run
(或相关函数)与
shell=True
一起使用时,它是显式使用
/bin/sh
。它不使用 your shell,也不会读取您的 zsh 初始化文件。你必须假设
/bin/sh
是一个通用的 Bourne 兼容 shell

像这样运行你的脚本是有效的...

python script.py

...因为脚本从您的 shell 继承了

$PATH
的值。您可以随时明确地致电
zsh
;而不是:

process = subprocess.run("which java", shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

你可以运行:

process = subprocess.run(["zsh", "-c", "which java", check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

或者,如果您的脚本需要

$PATH
中的特定目录才能工作,请在调用
os.environ['PATH']
之前通过设置
subprocess.run
来显式设置。

© www.soinside.com 2019 - 2024. All rights reserved.