首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何运行.sh并在Windows上通过文件关联从Java获取返回值

如何运行.sh并在Windows上通过文件关联从Java获取返回值
EN

Stack Overflow用户
提问于 2021-01-01 18:22:18
回答 1查看 568关注 0票数 2

背景

我正在编写一个运行在.sh文件中指定的.properties文件并获取其返回值的Java程序。.sh文件的路径是从.properties文件中指定的,如:

代码语言:javascript
运行
复制
command=C:/tmp/hoge.sh
args[0]=foo
args[1]=bar
args[2]=baz

Java程序将其读为:

代码语言:javascript
运行
复制
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=)。我想避免为开发环境准备专用的separately.
  • We文件,而生产环境fluently).
  • We之所以使用Windows版本,主要是因为两个原因: 1)我们从Java程序调用的中间件(它只支持Windows和RHEL,但不支持WSL环境);2)项目成员的技能集(由于代码覆盖率测量和

质量管理,只有少数成员可以同时使用和),因此希望尽可能避免在开发环境中使用额外的代码。

我已经尝试并证实了

为了在Windows环境中测试Java程序和.sh文件,我决定使用WSL2。

要在Windows上运行.sh,我已经为.sh文件设置了WSL2和修改过的文件关联。我在键HKEY_LOCAL_MACHINE\SOFTWARE\Classes\sh_auto_file\shell\open\command中添加了以下默认值,以便在WSL2上运行.sh

代码语言:javascript
运行
复制
"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运行WSL2,并正确地获得.sh的返回值。

代码语言:javascript
运行
复制
C:\tmp>hoge.sh

C:\tmp>echo %ERRORLEVEL%
5

hoge.sh的内容如下:

代码语言:javascript
运行
复制
sleep 1
exit 5

问题

Java程序在Linux上正确运行.sh文件。但是在Windows上,它会导致如下错误:

代码语言:javascript
运行
复制
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

问题

如何使用.sh上的文件关联从Java运行WSL2?或者,没有办法根据文件关联启动程序并在Java中获得返回值吗?

请注意,您可以通过java.awt.Desktop#open()启动带有文件关联的程序,但它没有获得返回值的方法。

还请注意,像下面这样为开发环境准备一个.properties文件需要非常艰苦的工作来满足我们的先决条件。

代码语言:javascript
运行
复制
command=wsl
args[0]=C:/tmp/hoge.sh
args[1]=foo
args[2]=bar
args[3]=baz
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-02 09:42:37

您可以让Windows和Linux版本运行BASH -c "yourcommand“,以简化操作系统处理上的差异。WSL安装BASH.EXE,用CMD.EXE确认它在那里:

代码语言:javascript
运行
复制
> where bash
C:\Windows\System32\bash.exe

如果在这两个操作系统上正确设置了路径,则只需使用"bash“作为命令:

代码语言:javascript
运行
复制
String [] cmd = new String[] { "bash" , "-c", "Insert command 'args[0]' 'args[1]' ... here"};

但是,要使上面的内容有效,您需要将cmd[2]构造为一个字符串,其中包含ars0..N值,如果它们还包含空格,则用引号进行转义,以便为脚本提供正确的参数。类似于:

代码语言:javascript
运行
复制
cmd[2] = prop.getProperty("command")+" "+ prop.getProperty("arg[0]") ...

如果您的路径没有设置,您可以调整启动代码以基于bash.exe/bin/bash选择os.name

代码语言:javascript
运行
复制
final String OS = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
//final boolean IS_WINDOWS = OS.startsWith("windows");
final boolean IS_LINUX   = OS.startsWith("linux");

String bash = IS_LINUX ? "/bin/bash" : "bash.exe" ;  // May need full path shown by where bash.EXE
String [] cmd = new String[] { bash , "-c", "Insert command  args[0] args[1] ... here"};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65532439

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档