Как перенаправить вывод Process Builder в строку?

Я использую следующий код для запуска построителя процессов.Я хочу знать, как я могу перенаправить его вывод в строку.

ProcessBuilder pb = new ProcessBuilder(System.getProperty("user.dir")+"/src/generate_list.sh", filename);
Process p = pb.start();

Я попытался с помощью ByteArrayOutputStream но, похоже, это не сработало.

8 ответов


Читать от InputStream. Вы можете добавить вывод в 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();

Использование Apache Commons IOUtils вы можете сделать это в одну строку:

ProcessBuilder pb = new ProcessBuilder("pwd");
String output = IOUtils.toString(pb.start().getInputStream());

вы можете сделать что-то вроде этого:

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

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

использование:

List<String> params = Arrays.asList("/bin/sh", "-c", "cat /proc/cpuinfo");
String result = runCommandForOutput(params);

Я использую этот точный код и он работает хорошо для одного или нескольких результатов. Вы также можете добавить обработчик потока ошибок.


для Java 7 и 8 это должно работать:

private String getInputAsString(InputStream is)
{
   try(java.util.Scanner s = new java.util.Scanner(is)) 
   { 
       return s.useDelimiter("\A").hasNext() ? s.next() : ""; 
   }
}

затем в вашем коде сделайте следующее:

String stdOut = getInputAsString(p.getInputStream());
String stdErr = getInputAsString(p.getErrorStream());

я бесстыдно украл это у:как перенаправить вывод Process Builder в строку?


после попытки обработки различных случаев (обработка как stderr, так и stdout и не блокирование любого из них, завершить процесс после таймаута, правильно экранируя косые черты, кавычки, специальные символы, пробелы,.... ) Я сдался и нашел Apache Commons Exec https://commons.apache.org/proper/commons-exec/tutorial.html это, кажется, делает все эти вещи довольно хорошо.

Я рекомендую всем, кому нужно вызвать внешний процесс в java использовать библиотеку Apache Commons Exec вместо того, чтобы изобретать ее снова.


просто добавить .inheritIO(); к строке process builder.

IE:

ProcessBuilder pb = new ProcessBuilder(script.sh).inheritIO();


в java 8 есть хороший поток lines (), который вы можете объединить со строкой.регистрация и система.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())
    }