This is a followup question to my other question : Run bat file in Java and wait
The reason i am posting this as a separate question is that the one i already asked was answered correctly. From some research i did my problem is unique to my case so i decided to create a new question. Please go read that question before continuing with this one as they are closely related.
Running the proposed code blocks the program at the waitFor invocation. After some research i found that the waitFor method blocks if your process has output that needs to be proccessed so you should first empty the output stream and the error stream. I did those things but my method still blocks. I then found a suggestion to simply loop while waiting the exitValue method to return the exit value of the process and handle the exception thrown if it is not, pausing for a brief moment as well so as not to consume all the CPU. I did this:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Test {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec(
"cmd /k start SQLScriptsToRun.bat" + " -UuserName -Ppassword"
+ " projectName");
final BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
final BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
new Thread(new Runnable() {
#Override
public void run() {
try {
while (input.readLine()!=null) {}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
try {
while (error.readLine()!=null) {}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
int i = 0;
boolean finished = false;
while (!finished) {
try {
i = p.exitValue();
finished = true;
} catch (IllegalThreadStateException e) {
e.printStackTrace();
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
System.out.println(i);
} catch (IOException e) {
e.printStackTrace();
}
}
}
but my process will not end! I keep getting this error:
java.lang.IllegalThreadStateException: process has not exited
Any ideas as to why my process will not exit? Or do you have any libraries to suggest that handle executing batch files properly and wait until the execution is finished?
Start cmd with the /c switch instead of /k and get rid of the start:
Process p = Runtime.getRuntime().exec(
"cmd /c SQLScriptsToRun.bat" + " -UuserName -Ppassword"
+ " projectName");
/k tells cmd: “Run that command and then stay open”, while /c says “Run that command and then exit.”
/k is for interactive use where you want an initializing batch file and afterwards still use the console.
Your main problem here, however, is that you are creating yet another process by using start. To run a batch file this is totally unnecessary and prevents you from knowing when the batch was run completely, since Java has a reference to the original cmd process you started, not the one you spawned with start.
In principle, this now looks like the following:
Java program starts
Java program runs cmd and instructs it to run start foo.bat and stay open for interactive input (/k)
Java memorizes the process ID (PID 42) to later reference that process
cmd (PID 42) starts
cmd (PID 42) runs start foo.bat
start foo.bat launches another instance of cmd, since that's what should happen to run batch files
cmd (PID 57005) starts
cmd (PID 57005) runs foo.bat
cmd (PID 57005) exits (This marks the event you'd like to know about)
cmd (PID 42) shows the prompt and obediently waits for input (unbeknownst to them the prompt is never seen by a user and no input will ever come ... but cmd (PID 42) waits ...)
Java likes to know whether the process is finished and checks PID 42
Yup, it's still there. Now what?
What you want (and what above change will do) is:
Java program starts
Java program runs cmd and instructs it to run foo.bat and close after running the command (/c)
Java memorizes the process ID (PID 42) to later reference that process
cmd (PID 42) starts
cmd (PID 42) runs foo.bat
cmd (PID 42) exits
Java likes to know whether the process is finished and checks PID 42
Hooray, the process is gone, the batch file has been run.
Related
I want to start a cmd command, then after the first command is done, I want to run a code to adjust some text in a file, then execute another command on the same cmd window. I don't know how to do that and everywhere I looked the answer is for the commands after each other which is not this case. the code for editing the text works fine without starting the cmd but if I execute the cmd command it does not change. code below.
public static void main(String[] args)throws IOException
{
try
{
Main m1 = new Main();
Process p= Runtime.getRuntime().exec("cmd /c start C:/TERRIERS/terrier/bin/trec_setup.bat");
p.waitFor();
/*code to change the text*/
m1.answerFile(1);
m1.questionFile(1);
/**********************/
//code to add another command here (SAME WINDOW!)
/************************/
}
catch(IOException ex){
}
catch(InterruptedException ex){
}
Execute cmd and send your command lines (.bat) to the standard input.
Process p = Runtime.getRuntime().exec("cmd");
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null)
System.out.println(line);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
try (PrintStream out = new PrintStream(p.getOutputStream())) {
out.println("C:/TERRIERS/terrier/bin/trec_setup.bat");
out.println("another.bat");
// .....
}
p.waitFor();
For starters, the \C option terminates CMD after executing the initial command. Use \K instead.
You won't be able to use waitFor() to detect when the initial command is done, because if you wait until the CMD terminates, you won't be able to re-use the same process.
Instead, you'll need to read the output of CMD process to detect when the batch file is complete and you are prompted for another command. Then write the next command line that you want to execute though the input stream of the Process.
Sounds like a pain. Why would do you need to use the same window?
My application uses some daemon subprocesses for subtasks. The subprocesses are launched using ProcessBuilder and working fine on their own, but then starting them as subprocesses every associated Process.isAlive() method return FALSE. As following, no access to process is possible.
Further investigation shows the subprocesses are not started at all (don't exist in Task Manager) with no error generated at all.
Daemons typically start a separate process and exit almost immediately, which makes checks like isAlive() useless.
Often the program will have a command line switch that make the program stay in the foreground, not becoming a daemon - use that if possible. Otherwise you'll need some other way of monitoring the daemon execution, for example using the daemon's PID file.
Is the command really running? Often there are weird little issues when trying to run a program from inside Java.
For example, the PATH environment variable may not be set correctly so it fails to load a dependency.
Use this method to see if there is any console output and what the exit code is. This uses the old Runtime class instead of ProcessBuilder. It can probably be adapted to use ProcessBuilder.
public static void runExe(String[] command) throws IOException {
Runtime runtime = Runtime.getRuntime();
long start = System.currentTimeMillis();
Process proc = runtime.exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
try {
while (true) {
// enter a loop where we read what the program has to say and wait for it to finish
// read all the program has to say
while (br.ready()) {
String line = br.readLine();
System.out.println("CMD: " + line);
}
try {
int exitCode = proc.exitValue();
System.out.println("exit code: " + exitCode);
// if we get here then the process finished executing
break;
} catch (IllegalThreadStateException ex) {
// ignore
}
// wait 200ms and try again
Thread.sleep(200);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Command took: " + (end - start) + "ms");
}
Is it possible to make java monitor if a cmd is done then runs another cmd?
For example...
btnStart.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent args)
{
try
{
String command = "cmd /c start "+DetectDrive+"\\starting.bat";
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException e1)
{
e1.printStackTrace();
}
if(checkbox.isSelected())
{
try
{
String command = "cmd /c start "+DetectDrive+"\\Stage1.bat";
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if(checkbox_1.isSelected())
{
try
{
String command = "cmd /c start "+DetectDrive+"\\Stage2.bat";
Process p = Runtime.getRuntime().exec(command);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
How do I make sure that once starting.bat finishing running in the cmd then if stage1 has been ticked then the stage1.bat will start running in the cmd???
And then after the stage1.bat finish running in the cmd, it will go backs to the code and check if stage2.bat is ticked, if it is, then stage2.bat will run.
Use Process.waitFor, but add /wait to your command to make then new process wait for the batch process to stop.
For example:
String command = "cmd /c start /wait Stage1.bat";
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
The new process creates a new batch process and then terminates without the /wait.
Use Process.waitFor(). It will wait until the command ends.
Process has a waitFor method
from the javadoc:
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.
All,
I originally had a shell script that called SQLLoader (Oracles data upload tool).
The problem was that SQLLoader takes a plain text password as input so I decided to build a Java application to call SQLLoader internally passing a decrypted password into the command string.
e.g.
sqlldr user/pass#DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv
So with my java wrapper it became this in my shell script
java -jar sqlloader.jar sqlloader.ctl mydata.csv
However a new problem developed when SQLLoader complained there was no file to load. After some head scratching it was discovered that a subsequent command in my shell script seemed to be executing while my java application was still running. Therefore it was behaving asynchronously.
The next command was moving the input file sqlloader was using before it could get a chance to use it. So I put a sleep command in of 20 seconds to give my java application time to run.
java -jar sqlloader.jar sqlloader.ctl mydata.csv
echo $?
sleep 20
if [ $? -ne 0 ]
then
echo "SQLLoader failed during execution, please check the log : "
mv mydata.csv
else
echo "SQLLoader successfully processed file : "
mv mydata.csv
fi
Does anyone know why unix is behaving this way, does Java execute my SQLLoader as a different user/ thread?
This is my java code:
Runtime Rt;
Process Prc;
Prc = Rt.exec("sqlldr user/decryptedpass#DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv);
system.exit(0);
I checked the Runtime Class for anything about it being Asynchronous but couldnt find anything
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
Any theories or suggestions?
Thanks
Yes. If you look at Runtime.exec again it does specify that it will launch a new process in the specified environment (e.g. independently of the current "environment" or as you put it asynchronously). You should use ProcessBuilder to create a Process and then waitFor that Process to finish before calling System.exit - which certainly isn't mandatory. Something like this
public static void main(String[] args) {
// String command = "/usr/bin/sleep 5";
List<String> command = new ArrayList<String>();
command.add("c:/cygwin/bin/sleep");
command.add("5");
ProcessBuilder pb = new ProcessBuilder(command);
BufferedReader is = null;
try {
System.out.println("Starting command " + command);
Process p = pb.start();
int ret = p.waitFor();
is = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
}
if (ret == 0) {
System.out.println("Command has completed.");
System.exit(ret);
} else {
System.out.println("Command completed with return code " + ret);
System.exit(ret);
}
} catch (Exception e) {
System.out.println("Caught Exception " + e.getMessage()
+ " running command " + command);
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
System.out.println("COMMAND FAILED");
System.exit(1);
}
You need to wait for process completion, you should also read all output (stdout and stderr) from the process you are starting.
If you call exit() after exec(), Java will do just that - exit immediatedly.
Here is an article that explains Runtime.exec pitfalls: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 (also consider the other pages).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I wanted to run a .cmd file from Java. I have something which works for me. Can someone help me understand possible failures of my program.
import java.io.IOException;
/*
How to run a batch .bat or .cmd file from Java?
1. I don't want the command window to open up. It should be in background.
2. Gracefully destroy any new process created.
3. Need to confirm the quality of the program with experts.
*/
public class RunBat {
public static void main(String args[]) {
Runtime run = Runtime.getRuntime();
//The best possible I found is to construct a command which you want to execute
//as a string and use that in exec. If the batch file takes command line arguments
//the command can be constructed a array of strings and pass the array as input to
//the exec method. The command can also be passed externally as input to the method.
Process p = null;
String cmd = "D:\\Database\\TableToCSV.cmd";
try {
p = run.exec(cmd);
p.getErrorStream();
System.out.println("RUN.COMPLETED.SUCCESSFULLY");
}
catch (IOException e) {
e.printStackTrace();
System.out.println("ERROR.RUNNING.CMD");
p.destroy();
}
}
}
Is my solution reliable? How can I make sure that once the .cmd is execute there is no processes hanging around.
Thanks.
I don't know what you are doing with p.getErrorStream(), You are not accesing it.
Way to determine result i.e. exit code of command executed is by adding following lines after
p = run.exec(cmd);
p.waitFor();
System.out.println(p.exitValue());
And put p.destroy() in finally block.
Hope this helps.
Execute your command as:
cmd.exe /C d:\database\tabletoCSV.cmd
See cmd.exe /? for more information:
> cmd /?
Starts a new instance of the Windows command interpreter
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
[...]
Like Carl just mentioned
You are not capturing any output error / success output.
Your are not making the process thread wait for exitValue.
Have you given a look at ProcessBuilder class?
Anyway , you can have a look at following code
Process proc = null;
Runtime rt = Runtime.getRuntime();
try {
proc = rt.exec(cmd);
InputStream outCmdStream = proc.getInputStream();
InputStreamReader outCmdReader = new InputStreamReader(outCmdStream);
BufferedReader outCmdBufReader = new BufferedReader(outCmdReader);
String outLine;
while ((outLine = outCmdBufReader.readLine()) != null) {
System.out.println(outLine);
}
InputStream errStream = proc.getErrorStream();
InputStreamReader errReader = new InputStreamReader(errStream);
BufferedReader errBufReader = new BufferedReader(errReader);
String errLine;
while ((errLine = errBufReader.readLine()) != null) {
System.out.println(errLine);
}
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (IOException e) {
e.printStackTrace();
System.out.println("ERROR.RUNNING.CMD");
proc.destroy();
}
}
Hope this helps
There's another thing wrong with this code that other answers don't indicate: If the process you start generates (console) output and you don't connect up its output stream, it will stall and fail for no apparent reason. For some programs and environments I've found it necessary to connect up separate threads to keep both the output and error streams drained. And to capture their output so you're not flying blind.
If you have a modern Java (post 1.5), you could also be looking at the ProcessBuilder class as a means to start up external programs.