I am creating a process using the below 2 lines
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(COMMAND);
where COMMAND = "program.exe". program.exe is on the system's PATH variable.
Now the problem is that this does not work only in Windows 2K8 R2. It works fine on every other flavour of windows (winXP, win2003)
The error reported is :
java.io.IOException: Cannot run program "program.exe": CreateProcess error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(Unknown Source)
You can run the program manually from the command line. You can run the program from within the parent process using the full path specification. I would say we can assume the program runs properly.
What else could be different? The environment the parent process is running under perhaps? I would check the PATH before launching the process. You are using Java. Too many Java programs use batch files to launch the JVM process. This batch file could be mucking with the PATH variable.
If this is your program and no batch file in involved I would check the current working directory when you run the parent program. It could affect what gets found at runtime as well.
Related
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 .sh and .properties files on our system. So I want to use the same .properties files on the development environment and the production environment, or at least I want to use the .properties files with simple string replacement (on the example above, what I have to do is just replace the command=C: to command=). I want to avoid to prepare the dedicated .properties files 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
You could make both Windows and Linux versions run BASH -c "yourcommand" to simplify the differences in OS handling. WSL installs BASH.EXE, confirm it is there with CMD.EXE:
> where bash
C:\Windows\System32\bash.exe
If your PATH is set correctly on both OS you can just use "bash" as the command:
String [] cmd = new String[] { "bash" , "-c", "Insert command 'args[0]' 'args[1]' ... here"};
For the above to work though you'd need to construct cmd[2] as one string containing the args[0..N] values separated by space AND escaped with quotes if they also contained spaces so that the correct parameters are given to your script. Something like:
cmd[2] = prop.getProperty("command")+" "+ prop.getProperty("arg[0]") ...
If your Path is not setup you can adjust your launch code to pick bash.exe or /bin/bash based on os.name:
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"};
Jar file class getting executed through command prompt but noClassDefFound when run through shell script object of QTP
I have written a class to fetch data from websphere MQ and saved it as MQTools.Jar runnable.
I try to create a shell scripting object and use Run command Exception in thread "main" java.lang.NoClassDefFoundError: bec/MQ/Tools/MQClass
Set objShell = CreateObject("Wscript.Shell")
If instr(1,objShell.Environment.item("classpath"), strJavaFilePath, 1) > 0 Then 'javafilepath is path to the runnable Jar
Else
objShell.Environment.item("classpath") = objShell.Environment.item("classpath") & ";"&strJavaFilePath
End If
objShell.Run("cmd /c set classpath="& objShell.Environment.item("classpath"))
intReturn = objShell.Run ("cmd /c java bec.MQ.Tools.MQClass" & " "& strCommandLineArgs, 1, true) 'This line throws noclassdeffound error
I use the same command, copy and paste into a command window, it runs very smoothly without errors. Can anybody please suggest
Got it...
The issue here is even if I add the classpath runtime in QTP, QTP will not fetch the classpath until you restart QTP. For a new machine, this problem will occur, for an old machine i.e. a machine where this script is already run before, the classpath would already have the required value in variable and won't come across this issue. This issue is similar to one I have posted earlier but yet to find a solution. Refresh system variable using vbscript/QTP
The problem statement is 'How to reflect changes in system env variables in QTP without having to restart QTP'
Solution: Might be with some geek but unknown to the world yet.
When I run:
new ProcessBuilder("kotlinc", "-help").start();
I get the error: Cannot run program "kotlinc": CreateProcess error=2, The system cannot find the file specified
I've tried:
If I check my path from windows, it contains C:\Apps\kotlinc\bin, and when I open explorer at that location, there's a file named kotlinc.
If I open cmd.exe anywhere, and run kotlinc, it works just fine.
If I print out my environment:
System.out.print(new ProcessBuilder("kotlinc", "-help").environment().get("Path"));
it contains C:\Apps\kotlinc\bin
If I run new ProcessBuilder("python3", "file.py").start(), it works just fine.
Rebooting my machine
Changing kotlinc to use the full file path is not an acceptable solution, as this is being run across multiple computers and platforms.
As far as I can tell, everything is setup correctly.
Why can't I run kotlinc from ProcessBuilder?
kotlinc is actually a batch file (kotlinc.bat), not a binary file. Therefore, you need to start it by executing the command cmd /c kotlinc.
I am trying to make a eclipse project in Java to launch commands with some buttons. The libraries of Ros fuerte (These ones i want to use) are correctly installed and concretly i am trying to launch a ros command from a Java File using:
String cmd = "roscore";
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(cmd);
If i launch this command from a current terminal it works, but if i do it from the java file i have a problem because the terminal doesnt recognize the command.
java.io.IOException: Cannot run program "roscore": java.io.IOException: error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:475)
at java.lang.Runtime.exec(Runtime.java:610)
at java.lang.Runtime.exec(Runtime.java:448)
at java.lang.Runtime.exec(Runtime.java:345)
at LaunchTerminal.main(LaunchTerminal.java:24)
I think that i need to add some path or similar but i dont find the information. Does anybody know how to do it?
Thank u.
only normal commands are possible to execute like rm or cd ... al others must be referenced with full path of context
Do the following if you are using the groovy distribution:
String cmd = "source /opt/ros/groovy/setup.bash && roscore";
I want to set a path in my Java program with this Windows command (this path contains some DLL files that are used in a native peripheral of my program):
c:\>path=%path%;"C:\Users\NetBeansProjects\IPTV1.7\3rd_party"
But this causes an exception when the program runs:
java.io.IOException: Cannot run program "path=%path%;C:\Users\NetBeansProjects\IPTV1.7\3rd_party\": CreateProcess error=2, The system cannot find the file specified
I don't know why I can set the path with no problem in the command prompt but then get an exception thrown in the code.
String path = "C:\\Users\\NetBeansProjects\\IPTV1.7\\3rd_party\\";
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("path=%path%;"+ path);
Your command
path=%path%;"C:\Users\NetBeansProjects\IPTV1.7\3rd_party"
is not a "real" windows command, but only a variable assignment, interpreted by your shell (cmd.exe), visible only in the same shell session and any commands (other programs) started from there.
When trying to execute this from Java with Runtime.exec(), the windows CreateProcess function tries to find a executable file with this strange name, which obviously does not exist (can't exist, I think), and you get this error.
Even if you could execute this, for example by calling cmd.exe, it would only influence this same cmd.exe process (and any programs started from there, not your own Java process (and programs started from here).
Depending on what you in fact want, you could, for example:
give the path with ProcessBuilder directly to the process which in fact needs it (like Aaron showed)
search by yourself for executable files, if you want this for finding commands in the next exec
put the variable assignment and other commands together in a .BAT or .CMD file and execute this.
When you type this on the command prompt, the cmd program processes it and changes the PATH variable for you. When you try this with Runtime, no cmd process is created and there is no command "path=%path%;C:\Users\NetBeansProjects\IPTV1.7\3rd_party\" on your harddisk (Windows actually tries to find a program with this exact name).
Put the commands in a .BAT or .CMD file. Windows automatically creates a cmd process to execute them for you.
You can use ProcessBuilder in java to spawn a process and control the environment that it gets. So you would use the ProcessBuilder environment method to set the PATH environment variable, then set the relevant command line, then launch. SO something like (untried):
ProcessBuilder b = new ProcessBuilder();
b.environment().put("PATH", whatever);
b.command(whatever);
Process p = b.start();