【发布时间】:2021-01-01 18:22:18
【问题描述】:
背景
我正在编写一个Java 程序,它运行.properties 文件中指定的.sh 文件并获取它的返回值。 .sh 文件的路径是从.properties 文件中指定的,例如:
command=C:/tmp/hoge.sh
args[0]=foo
args[1]=bar
args[2]=baz
Java 程序的读法如下:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputStream is = cl.getResourceAsStream("resources/command.properties");
Properties prop = new Properties();
prop.load(is);
List<String> list = new ArrayList<String>();
list.add(prop.getProperty("command"));
list.add(prop.getProperty("args[0]"));
list.add(prop.getProperty("args[1]"));
list.add(prop.getProperty("args[2]"));
ProcessBuilder pb = new ProcessBuilder(list);
Process p = pb.start();
int returnValue = p.exitValue();
这个程序在生产环境的 Linux 上运行。但由于开发环境管理的原因,我们使用 Windows 作为开发环境。
先决条件
- 我们的系统上有很多
.sh和.properties文件。所以我想在开发环境和生产环境上使用相同的.properties文件,或者至少我想使用.properties文件进行简单的字符串替换(在上面的例子中,我要做的就是替换command=C:到command=)。我想避免分别为开发环境和生产环境准备专用的.properties文件。 - 我们使用Windows版本的Java主要有两个原因:1)我们从Java程序调用的中间件(它只支持Windows和RHEL,不支持WSL环境),2)项目的技能会员(能流利使用 Windows 和 Linux 的会员只有少数)。
- 由于代码覆盖率测量和质量管理,我们希望尽可能避免仅在开发环境中使用的附加代码。
我已经尝试并确认的内容
为了在Windows环境下测试Java程序和.sh文件,我决定使用WSL2。
为了在 Windows 上运行 .sh,我设置了 WSL2 并修改了 .sh 文件的文件关联。我已将以下默认值添加到键 HKEY_LOCAL_MACHINE\SOFTWARE\Classes\sh_auto_file\shell\open\command 以在 WSL2 上运行 .sh:
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "$arg=\"%1\";wsl (\"/mnt/\"+[System.Char]::ToLower($arg[0])+$arg.Substring(2,$arg.Length-2) -replace '\\', '/'); exit $LASTEXITCODE"
在命令提示符下,我确认可以通过文件关联在 WSL2 上使用 Bash 运行 .sh,并正确获取 .sh 的返回值。
C:\tmp>hoge.sh
C:\tmp>echo %ERRORLEVEL%
5
hoge.sh的内容是:
sleep 1
exit 5
问题
Java 程序在 Linux 上正常运行 .sh 文件。但在 Windows 上,它会导致如下错误:
Exception in thread "main" java.io.IOException: Cannot run program "C:/tmp/hoge.sh": CreateProcess error=193, %1 is not a valid Win32 application
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
at org.example.Main.main(Main.java:16)
Caused by: java.io.IOException: CreateProcess error=193, %1 is not a valid Win32 application
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.<init>(ProcessImpl.java:386)
at java.lang.ProcessImpl.start(ProcessImpl.java:137)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
... 1 more
问题
如何在 WSL2 上通过文件关联从 Java 运行 .sh?或者,有没有办法根据文件关联启动程序并在Java中获取返回值?
请注意,您可以通过java.awt.Desktop#open() 启动具有文件关联的程序,但它没有获取返回值的方法。
另请注意,为如下所示的开发环境准备.properties 文件需要非常努力地满足我们的先决条件。
command=wsl
args[0]=C:/tmp/hoge.sh
args[1]=foo
args[2]=bar
args[3]=baz
【问题讨论】:
-
抱歉,如果我错过了问题中的这个细节,但是在这种情况下,您是否有理由需要运行 Windows 版本的 Java?我了解您的开发环境是Windows,但是您可以在WSL下安装运行Linux版本的Java吗?或者这(我猜)是否会破坏您在 Windows 开发环境下的调试或构建工作流程?
-
@NotTheDr01ds 我们使用Windows版本的Java主要是因为两个原因:1)我们从Java程序调用的中间件(它只支持Windows和RHEL,但不支持WSL环境), 2)项目成员的技能(能流利使用Windows和Linux的只有少数成员)。我已经为问题添加了细节。谢谢!
标签: java windows shell windows-subsystem-for-linux file-association