I have a code that execute an external program. And now I need that my application wait the end of the execution of that external program.
But I'm not shure how I supposed to do that. I tried some things but don't work.
public Image acquireImage() throws IOException, InterruptedException {
process = Runtime.getRuntime().exec("cmd.exe /c start "+ApplicationProperties.getPath()
+ "\\.wimdesktop\\Release\\Static_GenerateGain.exe");
process.waitFor();
System.out.println("EXIT: " + process.exitValue());
return copyImage();
}
The problem is that the System.out.println("EXIT: " + process.exitValue()); print 0 but the external program still running.
You are running cmd.exe and asking it to start a process in the background. So all you are seeing is cmd.exe exit status 0 after it launches your app - and that app may still be running.
If you want waitFor to apply to the sub-process just run the exe directly without the launch wrapper:
process = Runtime.getRuntime().exec(ApplicationProperties.getPath()
+ "\\.wimdesktop\\Release\\Static_GenerateGain.exe");
Note that if your EXE depends on environment variables set by CMD.EXE then you may need to try your original command without "start" for background process:
process = Runtime.getRuntime().exec("cmd.exe /c "+ApplicationProperties.getPath()
+ "\\.wimdesktop\\Release\\Static_GenerateGain.exe");
In both cases above you may run into second issue that the command freezes, this is because you are not reading the Stdout and error streams. There are many SO posts on how to do this.
Related
I have the following process :
Process p = Runtime.getRuntime().exec("cmd.exe /c start "
+file.getAbsolutePath() + "/script.sh");
TimeUnit.SECONDS.sleep(20);
if(p.isAlive()){
System.out.print("the process still running");
TimeUnit.SECONDS.sleep(10);
}
The problem is p.isAlive() always return false even though my process is still running (my script shell is still working).
How to fix it?
What do you think the START command does?
Start a program, command or batch script (opens in a new window.)
So, exec(...) starts a process for running cmd.exe, then the start command opens a window and starts a second process for running script.sh, then cmd.exe is done and exists, and the Process identified by p is no longer alive, since that process has ended.
Add /WAIT.
Start application and wait for it to terminate.
Process p = Runtime.getRuntime().exec(new String[] {
"cmd.exe", "/c", "start", "/wait",
file.getAbsolutePath() + "/script.sh" });
I have a java restful service method which executes a myscript.sh using processBuilder. My script takes one input (example - myscript.sh /path/to-a/folder).
Inside the script something like this
-> execute a command which is multithreaded i.e parallel processing
-> echo "my message"
Now when call my script from a linux command line it executes fine. First all the threads running finishes and then some text output from threaded command execution shown on terminal and then echo my message is shown.
But when I call the same script from java using processBuilder, the last echo message comes immidiately and execution ends.
Following the way I call my script from java
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash","/path/to/myscript.sh","/path/to/folder/data");
Process proc = processBuilder.start();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while((line = reader.readLine()) != null){
output.append(line + "\n");
}
System.out.println("### " + output);
I don't know whats happening, how to debug also.
Can someone enlighten me on how to get the same behaviour from shell script when run from terminal or from java processBuilder?
Use ProcessBuilder.redirectErrorStream(boolean redirectErrorStream) with argument true to merge the errors into output. Alternatively, you could also use the shell command syntax cmd 2>&1 to merge the error with output.
These are some of the cases why you may be immediately getting the output of the last echo statement (instead of the script taking time to run and return proper results):
Missing environment variables
The launched bash needs to source .bashrc or some such recource file
The launched bash may not be running in right directory (you can set this in ProcessBuilder)
The launched bash may not be finding some script/executable in its PATH
The launched bash may not be finding proper libraries in the path for any of the executables
Once you merge error, you would be able to debug and see the errors for yourself.
In your context, separate processes may be spawned in two ways:
1) Bash
/path/to/executables/executable &
This will spawn a new executable executable and you need to wait for it to finish. Here's an answer that will help you.
2) Java
Process exec = Runtime.getRuntime().exec(command);
status = exec.waitFor();
Essentially, you need to wait for the process to end before you start reading its std/err streams.
If I understand the problem correctly, adding just this line to your code should suffice: status = exec.waitFor() (Before you obtain the streams)
Here's the JavaDoc for Process.waitFor() :
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.
Returns:
the exit value of the subprocess represented by this Process object. By convention, the value 0 indicates normal termination.
Throws:
InterruptedException - if the current thread is interrupted by another thread while it is waiting, then the wait is ended and an InterruptedException is thrown
I am trying to automate some processes that were build in ancient times, for the sake of avoiding repetitive actions. It is required that the processes are started with one batch and stopped with another (this can not be changed btw).
So i made a commandline tool to do this (and many other repetitive stuff) and I have modelled a command that starts the 'startbatch' and a command that start the 'stopbatch'. Both commands work fine separatly (as I tested them separatly) but there seems to be a problem when i want execute them one after another (in the correct order ofcourse). I get the following error in new cmd.exe window:
The process cannot access the file because it is being used by another process.
the code that i am using to start the batches looks like this:
public void startBatchInDev(String company){
String startBatchFolder = locations.getLocationFor("startbatch");
try{
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd.exe /C cd \"" + startBatchFolder + "\" & start cmd.exe /k \"" + BATCHSTART + company.toLowerCase()+ "-dev" + BATCH_SUFFIX + "\"");
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
public void stopBatchInDev(String company){
String startBatchFolder = locations.getLocationFor("startbatch");
try{
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd.exe /C cd \"" + startBatchFolder + "\" & start cmd.exe /k \"" + BATCHSTOP + company.toLowerCase()+ "-dev" + BATCH_SUFFIX + "\"");
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
The names of the batchfiles are concatenated, but they are OK once the application is running.
The error message is quite clear, some file is locked and I can't access it because of it. Some googling confirms my suspicion, but I can't seem to find a solution for this. The hits in google are all about obvious uses of files, like an obvious shared resource. But in my case, i am not working on the same batch file. The stop and start batch are two different files. So I am actually starting to think that it might be the cmd.exe file that is being locked by windows...
So this question is actually two questions:
- what is the exact cause of the described problem?
- how do i programmatically fix this (if possible)?
thanks in advance!
So, basically, bat is not so great :-(
I was able to repro this from java, but I also found that this script:
#echo off
echo STOP
echo STOP >> E:\tmp\java\logfile.txt
C:\cygwin\bin\sleep.exe 1
echo STOP1 >> E:\tmp\java\logfile.txt
C:\cygwin\bin\sleep.exe 1
echo STOP2 >> E:\tmp\java\logfile.txt
When run twice like this:
start test.bat && start test.bat
Will fail with one or more messages like:
The process cannot access the file because it is being used by another process.
The reason is that " >> " redirection opens the file for Read/Write access but only FILE_SHARE_READ sharing. If two different programs attempt to open the file this way, one of them fails.
So, you cannot have two different batch files running at the same time and logging to the same file
You would think that launching a bat file from Java would be an easy task but no... I have a bat file that does some sql commands for a loop of values read from a text file. It is more or less like this:
FOR /F %%x in (%CD%\listOfThings.txt) do sqlcmd -Slocalhost\MSSQL %1 %2 -d %3 -i %CD%\SQLScripts\\%%x
exit
Don't worry about the specifics they are not important. What i want is to simply run this bat file from within Java and have it wait until execution is finished. Apparently it is not easy. What i have so far is this:
Runtime.getRuntime().exec("cmd /K start SQLScriptsToRun.bat"
+" -U"+getUser()
+" -P"+getPass()
+" " + projectName);
return true;
The problem is that the exec() method returns immediately. The bat file runs for a good 2-3 minutes. I tried removing the start but to no avail. I tried many variations but it got me nowhere. Any ideas on how to do this simple task?
You should not ignore the return value of .exec(). It gives you a Process object that you can waitFor(), like this:
final Process process = Runtime.getRuntime().exec("blahblahblah");
final int exitVal = process.waitFor();
// if exitVal == 0, the command succeeded
you need to use waitFor on the process exec call returns.
I have a synchronization problem in java.
I want my main thread to wait until process "p1" is finished.
I have used "waitfor" method. it has not worked for me.
Process p1 = runtime.exec("cmd /c start /MIN " + path + "aBatchFile.bat" );
p1.waitFor();
Could anybody help me please?
Thank you so much.
The problem here is that the Process object you get back from exec() represents the instance of cmd.exe that you start. Your instance of cmd.exe does one thing: it starts a batch file and then exits (without waiting for the batch file, because that's what the start command does). At that point, your waitFor() returns.
To avoid this problem, you should be able to run the batch file directly:
Process p1 = runtime.exec(path + "aBatchFile.bat");
p1.waitFor();
Alternately, try the /wait command line option:
Process p1 = runtime.exec("cmd /c start /wait /MIN " + path + "aBatchFile.bat" );
p1.waitFor();