I would like to execute foo.bat from within a Groovy program and have the resulting process' output redirected to stdout. Either a Java or Groovy code example would be fine.
foo.bat can take several minutes to run and generates a lot of output, so I would like to see the output as soon as it is generated, rather than having to wait until the process has completed before seeing all the output at once.
It is simple to redirect all your stream to standard output using inheritIO() method. This will print the output to the stdout of the process from which you are running this command.
ProcessBuilder pb = new ProcessBuilder("command", "argument");
pb.directory(new File(<directory from where you want to run the command>));
pb.inheritIO();
Process p = pb.start();
p.waitFor();
There exist other methods too, like as mentioned below. These individual methods will help redirect only required stream.
pb.redirectInput(Redirect.INHERIT)
pb.redirectOutput(Redirect.INHERIT)
pb.redirectError(Redirect.INHERIT)
This uses a class which reads all output the executed program generates and displays it in it's own stdout.
class StreamGobbler extends Thread {
InputStream is;
// reads everything from is until empty.
StreamGobbler(InputStream is) {
this.is = is;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
System.out.println(line);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac");
//output both stdout and stderr data from proc to stdout of this process
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream());
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream());
errorGobbler.start();
outputGobbler.start();
proc.waitFor();
If you're looking to do this with more Groovy and less java, this will print each line as it happens:
def cmd = "./longRunningProcess"
def process = cmd.execute()
process.in.eachLine { line -> println line }
Alternatively, if you want to see both stdout and stderr
def cmd = "./longRunningProcess"
def process = cmd.execute()
process.waitForProcessOutput( System.out, System.err )
Here's something a little simpler if you're just trying to grab the output of a simple command. You'll need to use threads like jitter does if you want to process in parallel or if your command takes stdin or generates stderr.
Use a buffered copy (like this) if you're getting lots of output.
import java.io.*;
public class test {
static void copy(InputStream in, OutputStream out) throws IOException {
while (true) {
int c = in.read();
if (c == -1) break;
out.write((char)c);
}
}
public static void main(String[] args) throws IOException, InterruptedException {
String cmd = "echo foo";
Process p = Runtime.getRuntime().exec(cmd);
copy(p.getInputStream(), System.out);
p.waitFor();
}
}
The following Groovy code will execute foo.bat and send the output to stdout:
println "foo.bat".execute().text
Asynchronous way to achieve it.
void inputStreamToOutputStream(final InputStream inputStream, final OutputStream out) {
Thread t = new Thread(new Runnable() {
public void run() {
try {
int d;
while ((d = inputStream.read()) != -1) {
out.write(d);
}
} catch (IOException ex) {
//TODO make a callback on exception.
}
}
});
t.setDaemon(true);
t.start();
}
{
Process p = ...;
inputStreamToOutputStream(p.getErrorStream(), System.out);
inputStreamToOutputStream(p.getInputStream(), System.out);
}
VerboseProcess
from jcabi-log can help you:
String output = new VerboseProcess(new ProcessBuilder("foo.bat")).stdout();
精彩评论