public class Test_Python
{
public static void main( String[] args ) throws IOException
{
String command = "cmd /k start cmd.exe /k \"cd C:\\Workspace\\supply\\environment\\ && setup.bat && python -V ";
Runtime.getRuntime().exec(command);
}
}
When I execute my code, the "python -V" does not work, it is not executed in the cmd window.
But if I delete the "setup.bat" from my command, the "python -V" is executed (I can read the version in the cmd window)
Also, if I manually start a cmd, type setup.bat and then python -V it works.
My batch file is used to set my working environment:
SET basedir=%~dp0
echo %basedir%
cmd /k "cd %basedir%\..\scripts && set PYTHONPATH=%basedir%\..\lib"
Is there any way to know why it fails?
Unlike python Java may need some help. As I can see you are running on Windows.
You invoke the Runtime.exec() method. The method returns a Process instance, and in it's documentation you can read
By default, the created process does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream(). The parent process uses these streams to feed input to and get output from the process. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the process may cause the process to block, or even deadlock.
So it is likely your process is started by the OS but gets blocked due to I/O restrictions. Get around that by reading the STDOUT and STDERR streams until your process finishes. One good programming model is visible at https://www.baeldung.com/run-shell-command-in-java
Now that we know the OS is not blocking the process, the issue may be inside the command itself. Note you concatenated several commands using the && operator. I do not have a windows system but searched a bit online:
https://www.ionos.com/digitalguide/server/know-how/windows-cmd-commands/
CommandA && CommandB (the second command is only run if the first was successful)
To check how the first part of your command exits run it separately in Java and do not forget to print the process.exitValue() method.
But looking at the whole picture, all you do with the first part is to change the working directory and set some environment variable. What stops you from running the ProcessBuilder methods? The example in the documentation directly sets the environment and directory.
Related
I'm starting a process (.bat) in java using java.lang.Process
Runtime.getRuntime().exec("cmd /c start /wait test.bat");
exitCode = process.waitFor();
The .bat process inturn calls .exe file, this .exe returns an exit code !=0 on error cases.
START /W test.exe
EXIT %ERRORLEVEL%
I want to get back the exit code returned from the batch file, but still I get back exitcode=0 always. I referred this but does not help.
Please let me know how can I get back the actual returned exit code from the process.
You are asking Java to launch CMD.EXE with the command start /wait test.bat which starts a second CMD.EXE process. There is EXIT %ERRORLEVEL% in the second CMD.EXE but there is no call in the scriptlet which tells the first CMD.EXE to use the status code as EXIT %ERRORLEVEL%. Thus you don't get the non-zero code of test.bat passed up to first CMD.EXE.
The fix is easy as you don't need to use start /wait, just change the command to avoid second CMD.EXE process and then the EXIT %ERRORLEVEL% of the batch script applies to the only CMD.EXE:
Process process = Runtime.getRuntime().exec("cmd /c test.bat");
Note that Runtime is not a good way to launch sub-processes, use ProcessBuilder instead with cmd passed as String[] not String so that you don't need to escape spaces in parameters.
Heed the warnings of the Process javadoc: failure
to promptly write the input stream or read the output stream of
the process may cause the process to block, or even deadlock. This means you should consume STDERR + STDOUT on different threads, or redirect STDERR to STDOUT, or redirect them to files or inherit IO streams - otherwise you may encounter problems. Many examples shown in StackOverflow won't work correctly.
I want to run and pass the arguments to ".cmd" file using Java program. I have checked the existing Solutions, but nothing is working in my case.
From Command line, I am running below command after getting into Directory C:/users/project/solr/bin
solr.cmd -s "C:users/github/example/solr-config"
So, solr.cmd gets arguments from the other Directory and then it runs the solr instance.
I have tried this, but I am not sure how to provide Parameters to Runtime.getRuntime():
Runtime run = Runtime.getRuntime();
Process p = null;
String cmd = "cmd /c start C:/users/project/solr/bin C:users/github/example/solr-config";
Process pr = run.exec(cmd);
I have followed this link: How do I run a batch file from my Java Application?
Could anyone please help me this.
I solved it by modifying cmd as solr.cmd expects -s also as argument:
String cmd = "cmd /c start C:/users/project/solr/bin/solr.cmd -s C:users/github/example/solr-config;
There is a difference between "it doesn't work" and "it doesn't show anything". As per the documentation:
By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream(). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.
If you want to retrieve the data that your process might have printed out on the standard I/O, you will have to read them from the abovementioned streams.
I am trying to make my Java program interact with Linux bash but something goes wrong. I have a simple executable prog that reads the one integer from stdin and outputs its square. Executing
echo 5 | ./prog
from bash itself prints correct answer 25 in stdout but running
import java.io.*;
public class Main {
public static void main(String[] args) throws InterruptedException, IOException {
Runtime run = Runtime.getRuntime();
Process proc = run.exec("echo 5 | ./prog");
proc.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while(br.ready())
System.out.println(br.readLine());
}
}
unexpectedly gives 5 | ./prog. What is the solution?
Java exec cannot run shell commands like that. If you want to run a shell command, you need to explicitly invoke the shell; e.g.
Process proc = run.exec(new String[]{"/bin/sh", "-c", "echo 5 | ./prog"});
For more details on what Java does with this, read the javadocs for exec(String) and exec(String[]). Note that these are "convenience methods", and you need to follow the chain of links to the underlying methods for a complete understanding of what the javadoc is saying.
If you want even more detail on how Java handles this, there is the source code ...
If you want to understand in depth why Java doesn't handle the shell syntax itself, you probably need to take a deep dive into the architecture and philosophy of UNIX / Linux systems, and the separation of concerns between application, operating system and command shell. Note that there are a myriad different shells, each with (potentially) different rules for quoting, argument splitting, redirection, pipes, etcetera. Most of the popular shells are similar, but that's just the way things panned out.
Explanation of the solution:
The reason for splitting the command by hand is that exec(String) won't split the command into a single command and arguments correctly. It can't. This is an example where there are two commands in a pipeline.
The reason for using "sh" is ... well ... you need a shell to parse and process a shell command line. Java's exec command does not support shell syntax ... as the javadoc explains.
The purpose of the "-c" option is explained by "man sh". Basically, sh -c "a b c" means "use 'sh' to run the command line 'a b c'".
FWIW, it is technically possible to construct and run a pipeline solely in Java (i.e. without relying on an external shell), but it is generally not worth the effort. You've already introduced a platform dependency by running external commands, so an extra dependency in the form of a specific shell command and syntax doesn't make things significantly worse.
I want to run linux script from Java program and continue to execute program only when script stop. I am not interested to read script output ... Can anybody help me?
Thanks a lot,
and excuse me for my bad English
Assuming all other threads are idle:
// run the script.
Process proc = Runtime.getRuntime().exec("/path/to/myscript");
// wait for the return code.
int ecode = proc.waitFor();
If you have more complex arguments to your script, or it needs to monitor STDOUT, STDERR, or needs other modifications (like feeding data to STDIN, or changing execution directory, environment variables, etc.) then you should do the same effective procedure, but instead of using Runtime.exec(...) you should build and start the Process manually. Read the Process javadoc and ProcessBuilder javadoc on how to set it up, and start it.
You can also launch the bash interpreter instead
Process proc = Runtime.getRuntime().exec("/bin/bash /path/to/myscript");
int ecode = proc.waitFor();
This may work in some generally broken cases when #rolfl solution may not work (non executable script file, #!/ header missing, etc)
I am trying to start a new process using Runtime.exec(), but my problem lies within using ssh to remote in and then run a java program there. Code:
test = "ssh -t username#host java packageName.ClassName portNumber (Other command line args for this class)"
Process proc = Runtime.getRuntime().exec(new String[] {"/bin/bash", "-c", test});
this doesn't fail or catch, but I need to be able to see the stdout for the newly running process and I don't.
Note: if I run ssh -t username#host java packageName.ClassName portNumber (Other command line args for this class) from the command line it works fine. I have the host setup to not require a password by using ssh keys.
Any ideas?
You need to use Process.getInputStream to obtain the output from the sub-process being created.
See this article for a good discussion on Runtime.exec.
I think you can ask for an input stream that corresponds to the stdout of the process and then print it on your standard output. If you need to see it after it executes, just call waitFor() method on the process so it finishes before you start printing.
Use getInputStream() to access returned process's stdout. You can also use facilities provided by ProcessBuilder.Redirect.