从Windows Python脚本运行WSL中的Linux应用程序

1 投票
1 回答
63 浏览
提问于 2025-04-12 20:08

在我的情况下,应用程序是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 个回答

2

简短版本

  • 检查你的 ~/.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。这让我们可以传递选项 ...
    • -lcl 强制启动登录 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 文档页面

撰写回答