Background
I am writing a Java program that runs a .sh file specified in .properties files and get its return value. The path of .sh file is specified from .properties files like:
command=C:/tmp/hoge.sh
args[0]=foo
args[1]=bar
args[2]=baz
And the Java program reads it like:
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();
This program runs on Linux in the production environment. But due to development environment management, we are using Windows as a development environment.
Prerequisites
- There are so many
.shand.propertiesfiles on our system. So I want to use the same.propertiesfiles on the development environment and the production environment, or at least I want to use the.propertiesfiles with simple string replacement (on the example above, what I have to do is just replace thecommand=C:tocommand=). I want to avoid to prepare the dedicated.propertiesfiles for the development environment and the production environment separately. - We are using the Windows version of Java mainly due to two reasons: 1) The middleware we call from Java program (it only supports Windows and RHEL, but doesn't support WSL environment), and 2) The skillset of project members (there are only a few members who can use both of Windows and Linux fluently).
- We want to avoid the additional code that is used only in the development environment as much as possible, because of the code coverage measurement and the quality management.
What I have tried and confirmed
To test the Java program and .sh file in the Windows environment, I have decided to use WSL2.
To run .sh on Windows, I have set up WSL2 and modified file association for .sh files. I have added following default value to the key HKEY_LOCAL_MACHINE\SOFTWARE\Classes\sh_auto_file\shell\open\command to run .sh on WSL2:
"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"
On the command prompt, I have confirmed that I can run .sh with Bash on WSL2 via the file association and get the return value of .sh properly.
C:\tmp>hoge.sh
C:\tmp>echo %ERRORLEVEL%
5
The content of hoge.sh is:
sleep 1
exit 5
Problem
The Java program runs .sh file properly on Linux. But on Windows, it causes an error like this:
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
Question
How can I run .sh from Java with file association on WSL2? Or, is there no way to launch programs according to file association and get the return value in Java?
Note that you can launch programs with the file association via java.awt.Desktop#open(), but it doesn't have a method to get the return value.
Note also that preparing a .properties file for the development environment like below needs very hard work on our prerequisites.
command=wsl
args[0]=C:/tmp/hoge.sh
args[1]=foo
args[2]=bar
args[3]=baz