I have command that takes about 4 minutes to complete execution. While executing the command from windows command prompt, it shows timing information and continuous output.
I want to show that output while running the command from my Java code.
Normal execution waits until the command exit and get the output. I want to get the output while running without waiting the command to finish.
Here is my code:
try{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(args);
String line="";
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
errorReader.lines().forEach(System.out::println);
process.waitFor();
System.out.println("---------------------------------------");
}
catch (Exception x){
System.out.println(x.getMessage());
}
Problem with this code is that it wits until the command ends then print all output at once.
The easiest solution is to stop using Runtime.exec, and use the more modern ProcessBuilder class instead. Its inheritIO() method will do exactly what you want:
ProcessBuilder builder = new ProcessBuilder(args);
builder.inheritIO();
Process process = builder.start();
You can’t read all of a process’s standard output or standard error at once. They can appear concurrently, and failing to read either one might or might not cause a process to hang. inheritIO() solves that problem.
For a reason I don't know about, The command I use, which is ffmpeg -i, to produce some resolutions of a video. It writes the output messages to the ErrorStream not OutputStream. When I printed the error stream first, I can see the output.
try{
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(args);
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
BufferedReader lineReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((line = err.readLine()) != null) {
System.out.println(line);
}
err.close();
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
process.waitFor();
System.out.println("---------------------------------------");
}
catch (Exception x){
System.out.println(x.getMessage());
}
Related
I'm playing a bit around with a small JAVA gui for the command line mode of cloudcompare.
Therefore I'm using a short snippet like these:
var processBuilder = new ProcessBuilder();
try {
var process = processBuilder
.command("open", "-a", "CloudCompare.app", "-n",
"--args", "-NO_TIMESTAMP", "-C_EXPORT_FMT", "LAS",
"-O", "/Users/se/pcl_1.las",
"-O", "/Users/se/pcl_2.las",
"-MERGE_CLOUDS")
.start();
String error, line;
BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = inputStream.readLine()) != null) {
System.out.println("line = " + line);
}
BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((error = errorStream.readLine()) != null) {
System.out.println("error = " + error);
}
var ret = process.waitFor();
System.out.printf("Program exited with code: %d", ret);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
But if I run it on macOS the command line window opens, the process runs normal, but I can't grab any of the informations in it. There is an option to write log files from cloudcompare. That works - the log file shows that all cloud processing steps are done.
Does anybody knows, how to grab the command line output?
As mentioned here, the /usr/bin/open command is not an option to grab the stdinput stream.
I change the command to /Applications/CloudCompare.app/Contents/MacOS/CloudCompare and it works.
The next question is, how to grab the InputStream with a thread. I tried some stack overflow topics, but it doesn't work at the moment, to get the output stream in realtime. It is flushed at the end of the CloudCompare process.
Here is my code:
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("cmd.exe /c kotlinc -script " + script.getAbsolutePath());
process.waitFor();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
All I want to have is an live output from the running script. Have somebody an idea how to do that?
Your process.waitFor() call is a blocking call, and only unblocks when the process ends, preventing your streams from working, since the streams will be closed when the process has ended.
Read from the stream in a separate thread that you call the .waitFor() in, or read from the stream before calling .waitFor()
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("cmd.exe /c kotlinc -script " + script.getAbsolutePath());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = bufferedReader.readLine()) != null){
System.out.println(line);
}
int exitValue = process.waitFor();
Incidentally, I would use a ProcessBuilder to get the Process, and not Runtime.getRuntime()
I have the following bash script, example.sh that has some lines of code.To reproduce what I need let's say that I have in the script the following lines:
#!/bin/bash
echo First part of program
sleep 3
echo Second part of program
So, when I run this directly from terminal I get the first part printed to the screen(First part of program) then wait 3 seconds and after that I get the next part on the screen(Second part of program). When I run this in java, I execute the scipt, wait 3 seconds then I get both parts printed on screen. Is there a way to get the same effect as when running from terminal?
EDIT!
This is my code:
public void executeCommand(String command) {
String line;
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
setOutput(output.toString());
output = new StringBuffer();
BufferedReader error = new BufferedReader(new InputStreamReader(p.getErrorStream()));
line="";
while ((line = error.readLine())!= null) {
output.append(line + "\n");
}
setError(output.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
If you start your script with the Process-Class then you can fetch the output of the script with for example:
ProcessBuilder pb = new ProcessBuilder("<bashname>", "<scriptpath>");
Process p = pb.start();
OutputStream ops = p.getOutputStream();
There must be the output immediatly.
SOLVED: redirect output and error into files using:
ProcessBuilder builder = new ProcessBuilder("sh",command);
builder.redirectOutput(new File("out.txt"));
builder.redirectError(new File("err.txt"));
try{
Process p = builder.start();
}catch(IOException e){
e.printStackTrace();
}
I have a project that use command prompt to complie java file,then print the result in console,this is mycode.
public static void main(String[] args) {
String line;
String output = "";
try {
Process p = Runtime.getRuntime().exec("java helloworld");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
input.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
System.out.print(output);
}
But it show nothing,although it work with another command,please help me.
As one of the commenters mentioned this might result in quite complex setups you are running into. It is most likely in your case that an error happens in java and you just do not see the output since error messages are written to the STDERR stream instead of STDOUT.
So there are two options (1) you take the code you already have and also try to read from the process' ErrorStream.
Bufferedreader error = new BufferedReader(new InputStreamReader(p.getErrorStream());
Or if you do not care whether or not the process you were starting was writing to STDERR or to STDOUT you can also use a ProcessBuilder and just set it up to redirect the error stream.
ProcessBuilder pb = new ProcessBuilder("java", "helloworld");
pb.redirectErrorStream(true); // this redirects STDERR to STDOUT
Process p = pb.start();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
input.close();
For the sake of simplicity I omitted all the boilerplate code and exception handling in the above. But I think you will get the idea.
Why are you using the Process builder and executing the same. Why not use JavaCompiler interface. See the documentation it is really well written.
I'm trying to capture output of an external program using java but I can't.
I have the code to show it, but not to put it into a variable.
I will use, for example, sqlplus to execute my oracle code "into exec.sql"
system/orcl#orcl : user/password/DB name
public static String test_script () {
String RESULT="";
String fileName = "#src\\exec.sql";
String sqlPath = ".";
String arg1="system/orcl#orcl";
String sqlCmd = "sqlplus";
String arg2 = fileName;
try {
String line;
ProcessBuilder pb = new ProcessBuilder(sqlCmd, arg1, arg2);
Map<String, String> env = pb.environment();
env.put("VAR1", arg1);
env.put("VAR2", arg2);
pb.directory(new File(sqlPath));
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader bri = new BufferedReader
(new InputStreamReader(p.getInputStream()));
while ((line = bri.readLine()) != null) {
RESULT+=line;
}
System.out.println("Done.");
}
catch (Exception err) {
err.printStackTrace();
}
return RESULT;
}
Because the Process will execute in a new thread it's likely that there is no output or incomplete output available when you come to your while loop.
Process p = pb.start();
// process runs in another thread parallel to this one
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
// bri may be empty or incomplete.
while ((line = bri.readLine()) != null) {
RESULT+=line;
}
So you need to wait for the process to complete before attempting to interact with it's output. Try using the Process.waitFor() method to pause the current thread until your process has had an opportunity to complete.
Process p = pb.start();
p.waitFor(); // wait for process to finish then continue.
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = bri.readLine()) != null) {
RESULT+=line;
}
This is only a simple approach you could also process the output of the process while it runs in parallel but then you would need to monitor the status of the process i.e. is it still running or has it completed, and the availability of output.
Use Apache Commons Exec, it will make your life much easier. Check the tutorials for information about basic usage. To read the command line output after obtaining an executor object (probably DefaultExecutor), create an OutputStream to whatever stream you wish (i.e a FileOutputStream instance may be, or System.out), and:
executor.setStreamHandler(new PumpStreamHandler(yourOutputStream));