ProcessBuilder pb = new ProcessBuilder("notepad");
Process p = pb.run();
System.out.println("Notepad is closed")
The code above will run fine and open up notepad. However the print statement will not print until I manually close the notepad window. This is because Java waits until the process is terminated. Is there anyway I can just open a process and check if the window has loaded?
The ProcessBuilder.start() method will not halt program execution.
You can use just like this:
ProcessBuilder pb = new ProcessBuilder("notepad");
Process p = pb.start();
System.out.println("This will print right after notepad is launched.")
You can then use the process object to read any output from the program, kill the program, or halt program execution until it is finished.
Here is the reference page: Process
You can use exitValue like this:
try {
// instead of 0 use the exit value of your started program to run some logic if it has failed
if (p.exitValue() != 0) {
}
} catch (IllegalThreadStateException e) {
// expected, here the logic will jump to if the program is still running
}
Related
In my Java application, I want to run a batch file that calls "scons -Q implicit-deps-changed build\file_load_type export\file_load_type"
It seems that I can't even get my batch file to execute. I'm out of ideas.
This is what I have in Java:
Runtime.
getRuntime().
exec("build.bat", null, new File("."));
Previously, I had a Python Sconscript file that I wanted to run but since that didn't work I decided I would call the script via a batch file but that method has not been successful as of yet.
Batch files are not an executable. They need an application to run them (i.e. cmd).
On UNIX, the script file has shebang (#!) at the start of a file to specify the program that executes it. Double-clicking in Windows is performed by Windows Explorer. CreateProcess does not know anything about that.
Runtime.
getRuntime().
exec("cmd /c start \"\" build.bat");
Note: With the start \"\" command, a separate command window will be opened with a blank title and any output from the batch file will be displayed there. It should also work with just `cmd /c build.bat", in which case the output can be read from the sub-process in Java if desired.
Sometimes the thread execution process time is higher than JVM thread waiting process time, it use to happen when the process you're invoking takes some time to be processed, use the waitFor() command as follows:
try{
Process p = Runtime.getRuntime().exec("file location here, don't forget using / instead of \\ to make it interoperable");
p.waitFor();
}catch( IOException ex ){
//Validate the case the file can't be accesed (not enought permissions)
}catch( InterruptedException ex ){
//Validate the case the process is being stopped by some external situation
}
This way the JVM will stop until the process you're invoking is done before it continue with the thread execution stack.
Runtime runtime = Runtime.getRuntime();
try {
Process p1 = runtime.exec("cmd /c start D:\\temp\\a.bat");
InputStream is = p1.getInputStream();
int i = 0;
while( (i = is.read() ) != -1) {
System.out.print((char)i);
}
} catch(IOException ioException) {
System.out.println(ioException.getMessage() );
}
ProcessBuilder is the Java 5/6 way to run external processes.
To run batch files using java if that's you're talking about...
String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);`
This should do it.
The executable used to run batch scripts is cmd.exe which uses the /c flag to specify the name of the batch file to run:
Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "build.bat"});
Theoretically you should also be able to run Scons in this manner, though I haven't tested this:
Runtime.getRuntime().exec(new String[]{"scons", "-Q", "implicit-deps-changed", "build\file_load_type", "export\file_load_type"});
EDIT: Amara, you say that this isn't working. The error you listed is the error you'd get when running Java from a Cygwin terminal on a Windows box; is this what you're doing? The problem with that is that Windows and Cygwin have different paths, so the Windows version of Java won't find the scons executable on your Cygwin path. I can explain further if this turns out to be your problem.
Process p = Runtime.getRuntime().exec(
new String[]{"cmd", "/C", "orgreg.bat"},
null,
new File("D://TEST//home//libs//"));
tested with jdk1.5 and jdk1.6
This was working fine for me, hope it helps others too.
to get this i have struggled more days. :(
I had the same issue. However sometimes CMD failed to run my files.
That's why i create a temp.bat on my desktop, next this temp.bat is going to run my file, and next the temp file is going to be deleted.
I know this is a bigger code, however worked for me in 100% when even Runtime.getRuntime().exec() failed.
// creating a string for the Userprofile (either C:\Admin or whatever)
String userprofile = System.getenv("USERPROFILE");
BufferedWriter writer = null;
try {
//create a temporary file
File logFile = new File(userprofile+"\\Desktop\\temp.bat");
writer = new BufferedWriter(new FileWriter(logFile));
// Here comes the lines for the batch file!
// First line is #echo off
// Next line is the directory of our file
// Then we open our file in that directory and exit the cmd
// To seperate each line, please use \r\n
writer.write("cd %ProgramFiles(x86)%\\SOME_FOLDER \r\nstart xyz.bat \r\nexit");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// Close the writer regardless of what happens...
writer.close();
} catch (Exception e) {
}
}
// running our temp.bat file
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec("cmd /c start \"\" \""+userprofile+"\\Desktop\\temp.bat" );
pr.getOutputStream().close();
} catch (IOException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
// deleting our temp file
File databl = new File(userprofile+"\\Desktop\\temp.bat");
databl.delete();
The following is working fine:
String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);
This code will execute two commands.bat that exist in the path C:/folders/folder.
Runtime.getRuntime().exec("cd C:/folders/folder & call commands.bat");
import java.io.IOException;
public class TestBatch {
public static void main(String[] args) {
{
try {
String[] command = {"cmd.exe", "/C", "Start", "C:\\temp\\runtest.bat"};
Process p = Runtime.getRuntime().exec(command);
} catch (IOException ex) {
}
}
}
}
To expand on #Isha's anwser you could just do the following to get the returned output (post-facto not in rea-ltime) of the script that was run:
try {
Process process = Runtime.getRuntime().exec("cmd /c start D:\\temp\\a.bat");
System.out.println(process.getText());
} catch(IOException e) {
e.printStackTrace();
}
I am using Runtime.getRuntime().exec function to launch independent GUI Java application for subroutine task.
The code used is in simple manner:
Runtime.getRuntime().exec("java -jar /home/user/jar.jar");
Executing the code doesn't cause any process launch nor error occured! ProcessBuilder has same effect.
Checked to work correctly on Windows.
As seems, on some platforms it is ignored on system level outside Java, as JRE does not return any kind of error.
EDT: I edited the code to read stderr and stdout by parallel thread to preserve main app execution:
Process p = Runtime.getRuntime().exec(runCmd);
new DaemonFailPrint(p).start();
Thread code is:
public class DaemonFailPrint extends Thread {
private Process process;
public DaemonFailPrint(Process process) {
this.process = process;
}
#Override
public void run() {
try {
process.waitFor();
String out = "";
while (process.getInputStream().available() > 0) {
out += (char) process.getInputStream().read();
}
out += System.lineSeparator();
while (process.getInputStream().available() > 0) {
out += (char) process.getErrorStream().read();
}
JOptionPane.showMessageDialog(null, out);
} catch (InterruptedException | IOException ex) {
JOptionPane.showMessageDialog(null, ex);
}
}
}
The result is: I got empty message box straight after subprocess is "launched".
The mean is Process object seems to be created and finished in same time, but no error out exists.
The Runtime::exec() does not wait for the process to exit, so if you want to detect errors in the executed program itself, you'd need to use something like:
Process process = Runtime.getRuntime().exec("java -jar /home/user/jar.jar");
int rc = process.waitFor();
if (rc != 0)
{
System.err.println("The process failed with error: " + rc);
}
It might be, that the jar is not found or cannot be executed etc., those errors you normally see on the console, but if you have no console, the only clue might be the return code.
You might also want to check here how to capture the output console:
Capturing stdout when calling Runtime.exec
Seems that you can use process.getInputStream() to connect to the output stream of the process. So you can simply copy it to the console to see what happened.
So far so good! I found the answer recently by myself, still don't have a reason why it works this way, but I suppose it's all about internal difference of handling new processes in VM's on different platforms.
I had to edit the code this way, and now it works:
String[] runcmd = {"java","-jar","/home/user/jar.jar"};
Runtime.getRuntime().exec(runcmd);
Now it seems to work perfect. As I see it fails to process the file and execute then command with parameters given as same string while no error thrown on Java code level, it's possibly lost in VM internals.
In my java program I am trying to run a different program through CMD with its output appearing in a command window in the foreground and then analyze the exit code of the child program (foo) in the main java program. Unfortunately, all I seem to be able to access is the exit code of the CMD window, which is always 0.
The following is a snippet of what I'm doing:
ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File(dir));
pb.command("cmd","/c","start","/wait","foo.exe",arg);
process = pb.start();
exitVal = process.waitFor();
but exitVal is always 0 regardless of how foo exits. How can I get just the exit code of foo?
I'm also pretty new to java so if there's a more elegant way of doing this, I'm open to suggestions.
I found a solution by modifying one of the things I had tried before to account for windows batch being finicky. The solution was to send another command to cmd to tell it to exit with the most recent error code. Earlier I had tried this by appending & exit %errorlevel% to the command but cmd variables are only updated at the end of each command line, not at the end of each command.
To force update, I used %^errorlevel% instead.
I am using this code:
ProcessBuilder builder = new ProcessBuilder("cmd.exe","java","invalidArg");
builder.redirectErrorStream(true);
try {
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()),10240);
String line;
if(processIsTerminated(p)){
line = r.readLine();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Is there a way to have the cmd window open as well when I use the .start() function? Currently it runs hidden and if there is no response I don't know if my command was ran successfully or it didn't run at all.
Well you have only 2 ways of running a command under Windows :
the way you go : you have full access to the input, output and error stream of the lauched command, but it has no window and anyway it would not write anything there since your program gets all the output
ask cmd.exe to start the other command in its own window (and optionnaly wait for its end). But then as the command writes to its own window, you program has no access to the input, output or error streams of the command
You can obtain that 2nd execution way with the start [/w] command arguments command of cmd.exe, just type start /w cmd.exe /c "echo foo & pause" in a cmd window to see what happens (the & pause is only there to let you some time to read the output ...)
From java, it would be :
ProcessBuilder builder = new ProcessBuilder("cmd.exe","/c", "start", "/w",
"cmd", "/c", "java invalidArg & pause");
I've been trying to use Java's ProcessBuilder to launch an application in Linux that should run "long-term". The way this program runs is to launch a command (in this case, I am launching a media playback application), allow it to run, and check to ensure that it hasn't crashed. For instance, check to see if the PID is still active, and then relaunch the process, if it has died.
The problem I'm getting right now is that the PID remains alive in the system, but the GUI for the application hangs. I tried shifting the ProcessBuilder(cmd).start() into a separate thread, but that doesn't seem to be solving anything, as I hoped it would have.
Basically the result is that, to the user, the program APPEARS to have crashed, but killing the Java process that drives the ProcessBuilder.start() Process actually allows the created Process to resume its normal behavior. This means that something in the Java application is interfering with the spawned Process, but I have absolutely no idea what, at this point. (Hence why I tried separating it into another thread, which didn't seem to resolve anything)
If anyone has any input/thoughts, please let me know, as I can't for the life of me think of how to solve this problem.
Edit: I have no concern over the I/O stream created from the Process, and have thus taken no steps to deal with that--could this cause a hang in the Process itself?
If the process writes to stderr or stdout, and you're not reading it - it will just "hang" , blocking when writing to stdout/err. Either redirect stdout/err to /dev/null using a shell or merge stdout/err with redirectErrorStream(true) and spawn another thread that reads from stdout of the process
You want the trick?
Don't start your process from ProcessBuilder.start(). Don't try to mess with stream redirection/consumption from Java (especially if you give no s**t about it ; )
Use ProcessBuilder.start() to start a little shell script that gobbles all the input/output streams.
Something like that:
#!/bin/bash
nohup $1 >/dev/null 2>error.log &
That is: if you don't care about stdout and still want to log stderr (do you?) to a file (error.log here).
If you don't even care about stderr, just redirect it to stdout:
#!/bin/bash
nohup $1 >/dev/null 2>1 &
And you call that tiny script from Java, giving it as an argument the name of the process you want to run.
If a process running on Linux that is redirecting both stdout and stderr to /dev/null still produce anything then you've got a broken, non-compliant, Linux install ;)
In other word: the above Just Works [TM] and get rid of the problematic "you need to consume the streams in this and that order bla bla bla Java-specific non-sense".
The thread running the process may block if it does not handle the output. This can be done by spawning a new thread that reads the output of the process.
final ProcessBuilder builder = new ProcessBuilder("script")
.redirectErrorStream(true)
.directory(workDirectory);
final Process process = builder.start();
final StringWriter writer = new StringWriter();
new Thread(new Runnable() {
public void run() {
IOUtils.copy(process.getInputStream(), writer);
}
}).start();
final int exitValue = process.waitFor();
final String processOutput = writer.toString();
Just stumbled on this after I had a similar issue. Agreeing with nos, you need to handle the output. I had something like this:
ProcessBuilder myProc2 = new ProcessBuilder(command);
final Process process = myProc2.start();
and it was working great. The spawned process even did output some output but not much. When I started to output a lot more, it appeared my process wasn't even getting launched anymore. I updated to this:
ProcessBuilder myProc2 = new ProcessBuilder(command);
myProc2.redirectErrorStream(true);
final Process process = myProc2.start();
InputStream myIS = process.getInputStream();
String tempOut = convertStreamToStr(myIS);
and it started working again. (Refer to this link for convertStreamToStr() code)
Edit: I have no concern over the I/O stream created from the Process, and have thus taken no steps to deal with that--could this cause a hang in the Process itself?
If you don't read the output streams created by the process then it is possible that the application will block once the application's buffers are full. I've never seen this happen on Linux (although I'm not saying that it doesn't) but I have seen this exact problem on Windows. I think this is likely related.
JDK7 will have builtin support for subprocess I/O redirection:
http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
In the meantime, if you really want to discard stdout/stderr, it seems best (on Linux) to invoke ProcessBuilder on a command that looks like:
["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]
Another solution is to start the process with Redirect.PIPE and close the InputStream like this:
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.redirectOutput(Redirect.PIPE);
builder.redirectErrorStream(true); // redirect the SysErr to SysOut
Process proc = builder.start();
proc.getInputStream().close(); // this will close the pipe and the output will "flow"
proc.waitFor(); //wait
I tested this in Windows and Linux, and works!
In case you need to capture stdout and stderr and monitor the process then using Apache Commons Exec helped me a lot.
I believe the problem is the buffering pipe from Linux itself.
Try to use stdbuf with your executable
new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");**
The -o0 says not to buffer the output.
The same goes to -i0 and -e0 if you want to unbuffer the input and error pipe.
you need to read the output before waiting to finish the cycle. You will not be notified If the output doesn't fill the buffer. If it does, it will wait until you read the output.
Suppose you have some errors or responses regarding your command which you are not reading. This would cause the application to stop and waitFor to wait forever. A simple way around is to re-direct the errors to the regular output.
I was spent 2 days on this issue.
public static void exeCuteCommand(String command) {
try {
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
ProcessBuilder builder = new ProcessBuilder();
if (isWindows) {
builder.command("cmd.exe", "/c", command);
} else {
builder.command("sh", "-c", command);
}
Process process = builder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
System.out.println("Cmd Response: " + line);
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}