java - ejemplo - ¿Cómo redirigir la salida de Process Builder a una cadena?
process java example (8)
Estoy usando el siguiente código para iniciar un generador de procesos. Deseo saber cómo puedo redirigir su salida a una Cadena.
ProcessBuilder pb = new ProcessBuilder(System.getProperty("user.dir")+"/src/generate_list.sh", filename);
Process p = pb.start();
Intenté usar ByteArrayOutputStream
pero no pareció funcionar.
Después de tratar de manejar diferentes casos (manejando stderr y stdout y no bloqueando ninguno de ellos, finalizo el proceso después del tiempo de espera, escapé correctamente barras, comillas, caracteres especiales, espacios, ....) Me rendí y encontré Apache Commons Exec https://commons.apache.org/proper/commons-exec/tutorial.html que parece estar haciendo todas estas cosas bastante bien.
Recomiendo a todos los que necesiten invocar procesos externos en Java que utilicen la biblioteca Apache Commons Exec en lugar de reinventarlos.
Ejemplo de Java 8:
public static String runCommandForOutput(List<String> params) {
ProcessBuilder pb = new ProcessBuilder(params);
Process p;
String result = "";
try {
p = pb.start();
final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
StringJoiner sj = new StringJoiner(System.getProperty("line.separator"));
reader.lines().iterator().forEachRemaining(sj::add);
result = sj.toString();
p.waitFor();
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
Uso:
List<String> params = Arrays.asList("/bin/sh", "-c", "cat /proc/cpuinfo");
String result = runCommandForOutput(params);
Utilizo este código exacto y funciona bien para resultados de líneas individuales o múltiples. También podría agregar un controlador de flujo de errores.
En java 8 hay una secuencia agradable de lines () que puedes combinar con String.join y System.lineSeparator ():
try (BufferedReader outReader = new BufferedReader(new InputStreamReader(p.getInputStream()))
{
return String.join(System.lineSeparator(), outReader.lines().collect(toList()));
// OR using jOOλ if you like reduced verbosity
return Seq.seq(outReader.lines()).toString(System.lineSeparator())
}
Lea de InputStream
. Puede agregar el resultado a un StringBuilder
:
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ( (line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
Para Java 7 y 8 esto debería funcionar:
private String getInputAsString(InputStream is)
{
try(java.util.Scanner s = new java.util.Scanner(is))
{
return s.useDelimiter("//A").hasNext() ? s.next() : "";
}
}
Luego en tu código, haz esto:
String stdOut = getInputAsString(p.getInputStream());
String stdErr = getInputAsString(p.getErrorStream());
Descaradamente lo robé de: ¿Cómo redirigir la salida de Process Builder a una cadena?
Puede hacer algo como esto:
private static BufferedReader getOutput(Process p) {
return new BufferedReader(new InputStreamReader(p.getInputStream()));
}
private static BufferedReader getError(Process p) {
return new BufferedReader(new InputStreamReader(p.getErrorStream()));
}
...
Process p = Runtime.getRuntime().exec(commande);
BufferedReader output = getOutput(p);
BufferedReader error = getError(p);
String ligne = "";
while ((ligne = output.readLine()) != null) {
System.out.println(ligne);
}
while ((ligne = error.readLine()) != null) {
System.out.println(ligne);
}
Solo agregue .inheritIO();
a la línea de construcción del proceso.
ES DECIR:
ProcessBuilder pb = new ProcessBuilder(script.sh).inheritIO();
Utilizando Apache Commons IOUtils puedes hacerlo en una sola línea:
ProcessBuilder pb = new ProcessBuilder("pwd");
String output = IOUtils.toString(pb.start().getInputStream());