从Windows Python脚本运行WSL中的Linux应用程序
在我的情况下,应用程序是OpenFoam,但其他一些Linux程序也会出现类似的问题。
我有一个用Windows的VS Code写的Python脚本(run_test.py):
import subprocess
command = "wsl python3 /mnt/wslg/distro/home/j/test.py"
subprocess.Popen(command, shell=True)
这个脚本会运行另一个在Linux的VS Code中写的Python脚本(test.py),这个脚本是在我的WSL环境下:
import subprocess
command = "cd $FOAM_RUN/airfopt && foamRun"
process=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = process.communicate()
if output:
print("Output:", output.decode())
if error:
print("Error:", error.decode())
当我通过Linux的VS Code启动test.py时,一切都正常,但当我运行"run_test.py"时,我遇到了一个错误:/bin/sh: 1: cd: can't cd to /airfopt
。
如果我把$FOAM_RUN/airfopt
换成完整路径/mnt/wslg/distro/root/OpenFOAM/root-11/run/airfopt
,就会出现新的错误:/bin/sh: 1: foamRun: not found
。
我觉得是因为run_test.py在Windows环境下运行test.py,而不是在Linux环境下。我想从run_test.py中运行test.py,但希望它在Linux环境下运行。
运行test.sh文件时也出现了同样的错误。
这是我第一次使用WSL,因为我需要OpenFoam的Linux版本(而不是blueCFD等),并且想把它和Windows的Python脚本连接起来。我在谷歌上搜索过,也在这里问过,甚至问了chatgpt,但没有得到好的答案。
感谢任何能帮助我的人!
1 个回答
简短版本
检查你的
~/.bashrc
、~/.bash_profile
和~/.profile
文件,看看$FOAM_RUN
是在哪里设置的。如果它是在
~/.bashrc
中定义的,那就把它移到~/.profile
中。把你第一个脚本中的命令定义改成:
command = "wsl -e bash -lc 'python3 /mnt/wslg/distro/home/j/test.py'"
另外,答案底部还有更好的方法,但在这里可能有点复杂。
附注:/mnt/wslg/distro/home/j/test.py
这个路径有点奇怪。虽然可以用,但应该和更短的 /home/j/test.py
是一样的。/mnt/wslg
是 WSLg 内部使用的挂载点,未来可能会改变(过去已经改过很多次)。没有保证 /mnt/wslg/distro
在未来的 WSL 版本中会继续指向发行版的根目录。
更多细节和其他选项
很可能,$FOAM_RUN
是在你的 ~/.bashrc
或类似文件中定义的。这个启动配置只有在你启动一个交互式 shell 时才会被读取。当第一个 Python 脚本运行时:
wsl python3 /mnt/wslg/distro/home/j/test.py
首先会隐式调用 bash -c
(或者你默认的 shell):
wsl -e bash -c 'python3 /mnt/wslg/distro/home/j/test.py'"
默认情况下,当用 -c
执行命令时,Bash 不会以交互模式运行,因此 ~/.bashrc
不会被读取。在某些发行版中,默认的 ~/.bashrc
甚至会进一步尝试防止交互使用。
你没有提到在 PowerShell 或 CMD 中运行:
wsl python3 /mnt/wslg/distro/home/j/test.py
... 是否能正常工作。如果我的回答是正确的,这应该会出现相同的错误信息。
你有几个选择:
首先,如果你需要在非交互式 shell 中使用
$FOAM_RUN
,最正确的方法是把它的定义从~/.bashrc
移到~/.profile
。后者在登录 shell 中会被读取。然后让 WSL 告诉bash
以登录 shell 运行,这样文件就会被处理。上面“简短版本”中的命令行:- 使用
wsl -e bash
显式启动 Bash。这让我们可以传递选项 ... -lc
:l
强制启动登录 shell,这样.profile
就会被读取。-c
用于在 shell 中执行下一个命令(你的 Python 脚本调用)。
- 使用
另一个选择是把变量定义留在
~/.bashrc
中,然后把你的命令行改成:command = "wsl -e bash -ic 'python3 /mnt/wslg/distro/home/j/test.py'"
唯一的区别是我们现在用
-i
启动 Bash,而不是-l
。这告诉 Bash 你正在启动一个“交互式” shell,并读取
~/.bashrc
。我一般认为这不是个好主意,因为你应该能假设交互式 shell 能处理(显然)需要输入的命令。如果你在
~/.bashrc
中有需要输入的命令,那么你的 Python 脚本会暂停并等待输入。这在subprocess
调用中可能不太好用——我记不太清楚了。无论如何,这可能不是你在测试脚本中想要的结果。
最后,最“正确”的方法可能是:
- 在Windows(调用)Python 环境中定义
$FOAM_RUN
- 同时定义(或修改)
WSLENV
变量,将FOAM_RUN
包含为你想从 Windows 进程传递到 WSL 环境的环境变量。
更多信息请查看在 WSL 和 Windows 之间共享环境变量以及相应的WSL 文档页面。
- 在Windows(调用)Python 环境中定义