java - processbuilder - linux - 提示未在输出流中捕获

时间:2013-04-30 22:39:46

标签: java linux shell prompt processbuilder

linux版:MINT 14 netbeans 7.2

我最近很喜欢编程,我遇到了这个困难。 我有一个带有2个jtextarea的GUI,一个我们输入命令的地方,一个命令输出的地方(第三个将实现错误(linux,而不是java) 这对我的原型来说还可以,到目前为止:

命令的输出进入文本区域,但它缺少提示,我尝试了很多东西,但无法绕过它, 我也浏览了很多常见问题,但提示在很多方面使用,但不在shell提示符中。 欢迎帮助。

我已经为流程构建器类插入了代码(现在请忽略大写字母等最佳实践,它只是一个原型,如果原型工作,我会有编程器)

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.io.StringWriter;
    import java.io.Writer;

    /**
     *
     * @author bane
     */
    public class myprocessBuilderRunCommand {
        public static String myprocessBuilderRunCommand(String command, boolean waitForResponse) {

    String response = "";

    ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
    pb.redirectErrorStream(true);

    System.out.println("Linux command: " + command);

    try {
    Process shell = pb.start();

    if (waitForResponse) {

    // To capture output from the shell
    InputStream shellIn;
            shellIn = shell.getInputStream();

    // Wait for the shell to finish and get the return code
    int shellExitStatus = shell.waitFor();
    System.out.println("Exit status" + shellExitStatus);

    response = convertStreamToStr(shellIn);

    shellIn.close();
    }

    }

    catch ( IOException | InterruptedException e) {
    System.out.println("Error occured while executing Linux command. Error Description: "
    + e.getMessage());
    }

    return response;
    }

    /*
    * To convert the InputStream to String we use the Reader.read(char[]
    * buffer) method. We iterate until the Reader return -1 which means
    * there's no more data to read. We use the StringWriter class to
    * produce the string.
    */

    public static String convertStreamToStr(InputStream is) throws IOException {

    if (is != null) {
    Writer writer = new StringWriter();

    char[] buffer = new char[1024];
    try {
    Reader reader;
            reader = new BufferedReader(new InputStreamReader(is,
     "UTF-8"));
    int n;
    while ((n = reader.read(buffer)) != -1) {
    writer.write(buffer, 0, n);
    }
    } finally {
    is.close();
    }
    return writer.toString();
    }
    else {
    return "";
    }
    }
    }

1 个答案:

答案 0 :(得分:0)

据我了解,您正在寻找一种从Java代码执行命令并在不同窗口中显示输出的方法。这是一个有效的示例,该命令执行命令echo 1,然后为输出true返回1,为输出false返回0,(在所有其他情况下均引发异常) 。这样,您可以将输出重定向到所需的任何位置。

我还添加了设置工作路径和环境变量的步骤,这对于您的特定示例不是必需的,因此您可以将其删除。

  1. 您可以复制将此代码粘贴为类,将其编译为jar并运行。
  2. 已在WSL Ubuntu 16.04中得到验证。
  3. 通过设置binaryCommand[0]="touch";binaryCommand[1]="1";,重新编译并运行.jar文件来验证设置工作目录的作用。

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    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 return the binary value of it's output if it 
         * is actually binary.
         * 
         * 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 boolean 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);
    
            // 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 shell = processBuilder.start();
    
                 // capture the output stream of the command
                 BufferedReader reader = new BufferedReader(new InputStreamReader(shell.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(shell.getErrorStream(), System.err)).start();
                 new Thread(new SyncPipe(shell.getInputStream(), System.out)).start();
                PrintWriter stdin = new PrintWriter(shell.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 = shell.waitFor();
                System.out.println("Return code = " + returnCode);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            return retrieveBooleanOutput(capturedCommandOutput);
        }
    
        private static boolean retrieveBooleanOutput(String commandOutput) throws Exception {
            if (commandOutput != null && commandOutput.length() == 1) { 
                if (commandOutput.contains("0")) {
                    return false;
                } else if (commandOutput.contains("1")) {
                    return true;
                }
            }
            throw new Exception("The output is not binary.");
        }
    
        /**
         * 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_;
    }