How to get an live output from runtime execution in java? - java

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()

Related

Show output while execute long-time running command Java without waiting RuntimeExec

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());
}

My code will continue only after process is finished via java

I am running an exec command through a process. I want that my program will keep running only after the process is finished. This is my code:
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("tools/jadx/bin/jadx.bat -d JavaProjects/");
//the rest of the code
System.out.println("Process is finished");
I need that the rest of the code will be executed only after the process is done, because it's depending on the process output. Any ideas?
I've got the answer and now it works!!!
Eevery process has input and output stream. my specific process had to empty his input buffer to continue running. All i added is the following code:
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("tools/jadx/bin/jadx.bat -d JavaProjects/");
out = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
int lExitCode = process.waitFor();
if (lExitCode == 0)
System.out.println("\n\n$$$$$ Process was finished successfully $$$$$\n\n");
else
System.out.println("\n\n$$$$$ Process was finished not successfully $$$$$\n\n");
waitFor is for this purpose:
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("tools/jadx/bin/jadx.bat -d JavaProjects/");
int lExitCode = process.waitFor();
//the rest of the code
if (lExitCode == 0)
System.out.println("Process was finished successfull.");
else
System.out.println("Process was finished not successfull.");

Bash real time output from java run

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();
}

How to run unix enq command in java program

Here is the unix command for adding a file to the queue.
enq -P QueueName:PrinterName FileName
Is it possible to run the above command using java.
Yes, it's possible using ProcessBuilder:
ProcessBuilder builder =
new ProcessBuilder("enq", "-P", "QueueName", "FileName");
Process process = builder.start();
InputStreamReader streamReader = new InputStreamReader(process.getInputStream());
BufferedReader reader = new BufferedReader(streamReader);
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
See: enq syntax
Process p = Runtime.getRuntime().exec(new String[]{"enq", "-P", "QueueName:PrinterName FileName"});

Capture the output of an external program in JAVA

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));

Categories