Print Runtime.getRuntime().exec() output live - java

I'm writing a Java program that is used to call a PHP script in set intervals. The PHP script outputs a lot of data, and it is the client's requirement that the Java program displays all the PHP script's output while the script runs.
The method I'm using is:
Runtime.getRuntime().exec(new String[]{"php", "file.php"});
Then using an InputStreamReader to grab output, primarily using examples from here. The problem I'm having is that the stream reader only outputs the data once the PHP script exits (which makes sense considering how the output is looped through).
How would I go about printing the script's output live while the script is running?

I did this by reading the output from a separate thread:
Process p = Runtime.getRuntime().exec(commands);
final InputStream stream = p.getInputStream();
new Thread(new Runnable() {
public void run() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(stream));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
// TODO
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// ignore
}
}
}
}
}).start();

For now I decided to go with Andrew Thompson's suggestion:
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
Process process = builder.start();
InputStreamReader istream = new InputStreamReader(process.getInputStream());
BufferedReader br = new BufferedReader(istream);
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
process.waitFor();
This is still not what I'm looking for though, so for now I'm leaving the question unanswered.

Related

Catching a RuntimeException 'cross-borders" in command line -- originated at one jar and thrown in another

I'm explicitly invoking JVM from within the system i'm developing, say systemA. this is by specs-- I have to process the command in another jre instance.
the command to do this is
java -cp thisJar.jar;thatJar.jar -Djava.security.manager=mySM -Djava.security.policy=my.policy TheClass
, and i'm running this command by the use of Process and ProcessBuilder:
StringBuilder sbResult = new StringBuilder();
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
Process p=null;
try {
p = builder.start();
p.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line = "";
while ((line = br.readLine()) != null)
sbResult.append(line+System.getProperty("line.separator"));
} catch (Throwable t) { commandResult.error.add(t); }
commandResult.text = sbResult.toString();
} catch (Throwable e1) { commandResult.error.add(e1); }
The type CommandResult is plain enough:
public static class CommandResult {
public String text="";
public List<Throwable> error = new LinkedList<>();
public int statusCode;
}
Whenever there's an error "of interest" in systemA, i'm catching and printing it out with e.printStackTrace(). with this, i'm expecting it to be captured by the above code.
However, ti isn't. the error is thrown and echoed on command prompt. however, the BufferedReader in the above code isn't seeing it. I'm guessing this is because the error is happening/originating in one jar and is thrown in a class in the other jar(?).
Is there a way to still capture this error programmatically?
the only way i can think of is have the class throwing the error write it to a file so that the class in the other jar can read it. or hand in the error text to the class in the other jar by invoking a method of it. but there must be a better solution.
TIA.
//--------------------------
UPDATE
following AR.3's useful suggestion, tried the following:
StringBuilder sbResult = new StringBuilder();
ProcessBuilder builder = new ProcessBuilder(command);
Process p=null;
try {
p = builder.start();
p.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line = "";
while ((line = br.readLine()) != null)
sbResult.append(line+System.getProperty("line.separator"));
} catch (Throwable t) { commandResult.error.add(t); }
commandResult.text = sbResult.toString();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String line = "";
while ((line = br.readLine()) != null)
sbResult.append(line+System.getProperty("line.separator"));
} catch (Throwable t) { commandResult.error.add(t); }
commandResult.text += sbResult.toString();
} catch (Throwable e1) { commandResult.error.add(e1); }
and
StringBuilder sbResult = new StringBuilder();
ProcessBuilder builder = new ProcessBuilder(command);
Process p=null;
try {
p = builder.start();
p.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String line = "";
while ((line = br.readLine()) != null)
sbResult.append(line+System.getProperty("line.separator"));
} catch (Throwable t) { commandResult.error.add(t); }
commandResult.text = sbResult.toString();
} catch (Throwable e1) { commandResult.error.add(e1); }
still not seeing that exception. no change from before.
There is no concept of an exception thrown "cross-borders" between Java applications. The forking process and the subprocess are completely independent processes running in different JVMs. Normally an exception would be printed on the error stream of the subprocess. In order to detect such an exception or any error printed on the error stream, you'd need to read that stream, in a way similar to what you did with the output stream.
However, in this case you should remove the statement builder.redirectErrorStream(true); since this statement will redirect the error stream to the output stream, making it difficult to distinguish between the two types of output. In order to catch error output, just read the Process#getErrorStream:
sbResult = new StringBuilder();
// this read the error stream of the subprocess
try (BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))) {
String line = "";
while ((line = br.readLine()) != null) {
sbResult.append(line+System.getProperty("line.separator"));
}
// errorString would contain the error generated by the subprocess, including thrown exceptions
commandResult.errorString = sbResult.toString();
}

Execute Runtime.getRuntime().exec(... command at server and get the client results

I want to check the tasks running on my clients, to avoid illegal programs from been executed
Is there a way to do that?
The code im trying to apply is:
try {
String line;
Process p = Runtime.getRuntime().exec(System.getenv("windir") +"\\system32\\"+"tasklist.exe");
BufferedReader input =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line); //<-- Parse data here.
}
input.close();
} catch (Exception err) {
err.printStackTrace();
}
Thank you

Get the output from executed commands through android app

I'm performing the following code to execute linux commands in my android application that I'm creating:
public void RunAsRoot(String[] cmds){
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd+"\n");
}
os.writeBytes("exit\n");
os.flush();
}
I want to know if there is a way to know what the command is returning after it is executing. for example, if I do "ls" I would like to see what the command wold normally output.
try this code :
try {
Process process = Runtime.getRuntime().exec("ls");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder result=new StringBuilder();
String line = "";
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
TextView tv = (TextView)findViewById(R.id.textView1);
tv.setText(result.toString());
}
catch (IOException e) {}
Let's go by a "String function" example
String shell_exec(String s)
{
String line="",output="";
try
{
Process p=Runtime.getRuntime().exec(new String[]{"sh","-c",s});
BufferedReader b=new BufferedReader(new InputStreamReader(p.getInputStream()));
while((line=b.readLine())!=null){output+=line+"\r\n";}
}catch(Exception e){return "error";}
return output;
}
Now just use it:
String s=shell_exec("ls /data/data/com.mycompany.myapp");

Read/Write to command-line .exe Java

I'm trying to launch a process in java, read the output, write to the program, then read what it responds with. From all the other answers on SO, this is what I have come up with:
class Main
{
public static void main(String[] args) {
String line = "";
try {
ProcessBuilder pb = new ProcessBuilder("C:\\myProgram.exe");
Process p = pb.start();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
output.write("foo");
output.newLine();
output.flush();
while ((line = input.readLine()) != null) {
System.out.println(line);
}
p.destroy();
}
catch (IOException e){
}
}
}
It launches the program, and gives me the output just as expected.
When i write foo, I expect the program to come back with another response, but it never does.
What am I doing wrong?

Java Process can't get ErrorStream message

everyone, I have a process that needs to get standard output and log/error/exception output from the subprocess. The standard output is fine, but I can't get ErrorStream, therefore the program is stuck there because of that. Here is my simple code. There is nothing magic, but why can't I get the error stream here? Thanks for looking at it.
BufferedReader standard =
new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader error =
new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
while ((line = standard.readLine()) != null) {
System.out.println(line);
}
while ((line = error.readLine()) != null) {
System.out.println(line);
}
Now, as suggested, i used two threads to process the output and error streams, but still had the same problem, as follows. Can anybody give me some insights? Thanks.
ProcessBuilder pb = new ProcessBuilder(listArgs);
pb.redirectErrorStream();
Process process = pb.start();
StreamThread output = new StreamThread(process.getInputStream());
StreamThread error = new StreamThread(process.getErrorStream());
output.start();
error.start();
while (true) {
try {
output.join();
break;
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
The definition of the StreamThread:
public static class StreamThread extends Thread{
private InputStream input = null;
public StreamThread(InputStream in){
input = in;
}
String line = null;
public void start(){
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
try{
while( (line=reader.readLine()) != null ){
System.out.println(line);
}
reader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
Look at your loops:
while ((line = standard.readLine()) != null) {
System.out.println(line);
}
while ((line = error.readLine()) != null) {
System.out.println(line);
}
You're going to keep reading from the output stream until it's finished - which is likely to be when the process terminates. Only then do you start reading the error stream.
You should probably put at least one of these into a different thread, so you can read from both streams at the same time.

Categories