我正在 IPython 笔记本中交互地开发一个包装类。 这个包装类调用用 java 编写的命令行程序,因此我需要访问用于编译该程序的相同版本的 java 运行时。
但是,我注意到在笔记本中使用方便的
!
运算符,生成的 shell 实例与在我的终端中使用
zsh
时不同。 这得到了确认:
!which java # from within notebook cell
'/usr/bin/java'
$ which java # on my zsh terminal
/opt/homebrew/opt/openjdk@11/bin/java
运行
echo $PATH
也为每个路径产生了不同的路径。
然后我遇到了
这个
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
生成的shell能够访问我系统上与终端相同的
'/usr/bin/java'
,但
!
生成的shell却无法访问?
zsh
on my system as the terminal, but the shell spawned by
subprocess
unable to?
你所觀察到的行為與 IPython 在子程序中設定環境變數的方式有關,特別是它處理
PATH
的方式。儘管連結
~/.zshrc
到
~/.zshenv
會影響由
!
使用的 shell,但它不會影響
subprocess
使用的環境。
以下是如何解決這個問題,並確保你的 Python 腳本使用正確 Java 版本的方法:
1. 明確設定
PATH
環境變數:
在你的 Python 腳本或筆記本儲存格中,明確地設定
PATH
環境變數,以包含你想要的 Java 可執行檔的路徑。你可以使用
os.environ
來執行此操作:
import os
import subprocess
# 取得目前的 PATH
current_path = os.environ['PATH']
# 將你想要的 Java 路徑新增到 PATH 的開頭
java_path = '/opt/homebrew/opt/openjdk@11/bin'
os.environ['PATH'] = f'{java_path}:{current_path}'
# 現在執行你的子程序
process = subprocess.run("which java", shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode("utf-8").strip()
print(output) # 這應該會輸出 '/opt/homebrew/opt/openjdk@11/bin/java'
2. 直接使用 Java 可執行檔的完整路徑:
在你的
subprocess
呼叫中,不要依賴
PATH
來尋找
java
,而是提供可執行檔的完整路徑:
import subprocess
java_path = '/opt/homebrew/opt/openjdk@11/bin/java'
process = subprocess.run([java_path, '-version'], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode("utf-8").strip()
print(output)
這些方法可以讓你繞過從
PATH
中尋找 Java 可執行檔的問題,並確保你的腳本使用正確的版本。
請記住,在修改
PATH
環境變數時要小心,因為這可能會影響在你 Python 腳本中執行的其他程序。建議在修改後將其恢復為原始值,或使用更具體的方法,例如直接指定可執行檔的路徑。