it-swarm.com.de

Wie leite ich die Ausgabe von Process Builder in einen String um?

Ich verwende den folgenden Code, um einen Process Builder zu starten. Ich möchte wissen, wie ich seine Ausgabe in einen String umleiten kann.

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

Ich habe versucht, ByteArrayOutputStream zu verwenden, aber es schien nicht zu funktionieren.

54
Ankesh Anand

Lesen Sie aus dem InputStream. Sie können die Ausgabe an ein StringBuilder anhängen:

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();
63
Reimeus

Mit Apache Commons IOUtils können Sie dies in einer Zeile tun:

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

Java 8 Beispiel:

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

Verwendung:

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

Ich benutze genau diesen Code und er funktioniert gut für einzeilige oder mehrzeilige Ergebnisse. Sie können auch einen Fehlerstrom-Handler hinzufügen.

10
Greg T

Sie könnten so etwas tun:

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

Für Java 7 und 8 sollte dies funktionieren:

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

Führen Sie dann in Ihrem Code Folgendes aus:

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

Ich habe das schamlos gestohlen aus: Wie leite ich die Ausgabe von Process Builder in einen String um?

4
Michael Potter

Fügen Sie einfach .inheritIO(); zur Process Builder-Zeile hinzu.

IE:

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

3
thouliha

Nachdem ich versucht hatte, verschiedene Fälle zu behandeln (sowohl stderr als auch stdout und keine davon zu blockieren), beende ich den Prozess nach einer Zeitüberschreitung, wobei Schrägstriche, Anführungszeichen, Sonderzeichen, Leerzeichen usw. ordnungsgemäß ausgeblendet wurden. Ich gab auf und fand Apache Commons Exec https://commons.Apache.org/proper/commons-exec/tutorial.html das scheint all dies zu tun Dinge ziemlich gut.

Ich empfehle jedem, der einen externen Prozess in Java) aufrufen muss, um die Apache Commons Exec-Bibliothek zu verwenden, anstatt sie erneut zu erfinden.

2
L.R.

In Java 8 gibt es einen Nice lines () Stream, den Sie mit String.join und System.lineSeparator () kombinieren können:

    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())
    }
1
Novaterata

Lösungen

  • Dieser Code ist ein laufendes Beispiel für die allgemeine Lösung Ihrer Frage:

Wie leite ich die Ausgabe von Process Builder in einen String um?

  • Dank geht an Greg T, nachdem er mehrere Lösungen ausprobiert hat, um verschiedene Befehle auszuführen und deren Ausgaben zu erfassen. Die Antwort von Greg T enthielt die Essenz der jeweiligen Lösung. Ich hoffe, dass das allgemeine Beispiel für jemanden von Nutzen ist, der mehrere Anforderungen kombiniert und gleichzeitig die Ausgabe erfasst.
  • Um Ihre spezielle Lösung zu erhalten, können Sie ProcessBuilder pb = new ProcessBuilder(System.getProperty("user.dir")+"/src/generate_list.sh", filename); auskommentieren, die Zeile auskommentieren und auskommentieren: ProcessBuilder processBuilder = new ProcessBuilder(commands);.

Funktionalität

  • Es ist ein funktionierendes Beispiel, das den Befehl echo 1 Ausführt und die Ausgabe als String zurückgibt.
  • Ich habe außerdem das Festlegen eines Arbeitspfads und einer Umgebungsvariablen hinzugefügt, die für Ihr bestimmtes Beispiel nicht erforderlich sind, damit Sie sie löschen können.

Verwendung & Überprüfung

  • Sie können diesen Code kopieren, als Klasse einfügen, in jar kompilieren und ausführen.
  • Es ist in WSL Ubuntu 16.04 verifiziert.
  • Das Festlegen des Arbeitsverzeichnisses wird überprüft, indem Sie binaryCommand[0]="touch"; Und binaryCommand[1]="1"; Festlegen, die Datei .jar Neu kompilieren und ausführen.

Einschränkungen

  • Wenn die Pipe voll ist (aufgrund einer "zu großen" Ausgabe), bleibt der Code hängen.

Code

import Java.io.BufferedReader;
import Java.io.File;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.PrintWriter;
import Java.util.Arrays;
import Java.util.Map;
import Java.util.StringJoiner;

public class GenerateOutput {

    /**
     * This code can execute a command and print the output accompanying that command.
     * compile this project into a .jar and run it with for example:
     * Java -jar readOutputOfCommand.jar
     * 
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        boolean answerYes = false; // no yes answer to any command prompts is needed.

        // to execute a command with spaces in it in terminal, put them in an array of Strings.
        String[] binaryCommand = new String[2];

        // write a command that gives a binary output:
        binaryCommand[0] = "echo";
        binaryCommand[1] = "1";

        // pass the commands to a method that executes them
        System.out.println("The output of the echo command = "+executeCommands(binaryCommand,answerYes));
    }

    /**
     * This executes the commands in terminal. 
     * Additionally it sets an environment variable (not necessary for your particular solution)
     * Additionally it sets a working path (not necessary for your particular solution)
     * @param commandData
     * @param ansYes
     * @throws Exception 
     */
    public static String executeCommands(String[] commands,Boolean ansYes) throws Exception {
        String capturedCommandOutput = null;
        System.out.println("Incoming commandData = "+Arrays.deepToString(commands));
        File workingDirectory = new File("/mnt/c/testfolder b/");

        // create a ProcessBuilder to execute the commands in
        ProcessBuilder processBuilder = new ProcessBuilder(commands);
        //ProcessBuilder processBuilder = new ProcessBuilder(System.getProperty("user.dir")+"/src/generate_list.sh", "a");

        // this is not necessary but can be used to set an environment variable for the command
        processBuilder = setEnvironmentVariable(processBuilder); 

        // this is not necessary but can be used to set the working directory for the command
        processBuilder.directory(workingDirectory);

        // execute the actual commands
        try {

             Process process = processBuilder.start();

             // capture the output stream of the command
             BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            StringJoiner sj = new StringJoiner(System.getProperty("line.separator"));
            reader.lines().iterator().forEachRemaining(sj::add);
            capturedCommandOutput = sj.toString();
            System.out.println("The output of this command ="+ capturedCommandOutput);

             // here you connect the output of your command to any new input, e.g. if you get prompted for `yes`
             new Thread(new SyncPipe(process.getErrorStream(), System.err)).start();
             new Thread(new SyncPipe(process.getInputStream(), System.out)).start();
            PrintWriter stdin = new PrintWriter(process.getOutputStream());

            //This is not necessary but can be used to answer yes to being prompted
            if (ansYes) {
                System.out.println("WITH YES!");
            stdin.println("yes");
            }

            // write any other commands you want here

            stdin.close();

            // this lets you know whether the command execution led to an error(!=0), or not (=0).
            int returnCode = process.waitFor();
            System.out.println("Return code = " + returnCode);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return capturedCommandOutput;
    }


    /**
     * source: https://stackoverflow.com/questions/7369664/using-export-in-Java
     * @param processBuilder
     * @param varName
     * @param varContent
     * @return
     */
    private static ProcessBuilder setEnvironmentVariable(ProcessBuilder processBuilder){
        String varName = "variableName";
        String varContent = "/mnt/c/testfolder a/";

        Map<String, String> env = processBuilder.environment();
         System.out.println("Setting environment variable "+varName+"="+varContent);
         env.put(varName, varContent);

         processBuilder.environment().put(varName, varContent);

         return processBuilder;
    }
}


class SyncPipe implements Runnable
{   
    /**
     * This class pipes the output of your command to any new input you generated
     * with stdin. For example, suppose you run cp /mnt/c/a.txt /mnt/b/
     * but for some reason you are prompted: "do you really want to copy there yes/no?
     * then you can answer yes since your input is piped to the output of your
     * original command. (At least that is my practical interpretation might be wrong.)
     * @param istrm
     * @param ostrm
     */
    public SyncPipe(InputStream istrm, OutputStream ostrm) {
        istrm_ = istrm;
        ostrm_ = ostrm;
    }
    public void run() {

      try
      {
          final byte[] buffer = new byte[1024];
          for (int length = 0; (length = istrm_.read(buffer)) != -1; )
          {
              ostrm_.write(buffer, 0, length);                
              }
          }
          catch (Exception e)
          {
              e.printStackTrace();
          }
      }
      private final OutputStream ostrm_;
      private final InputStream istrm_;
}
0
a.t.