【问题标题】:Better way to run pipe command using apache commons exec使用 apache commons exec 运行管道命令的更好方法
【发布时间】:2018-04-23 19:21:20
【问题描述】:

我正在使用 apache commons exec 运行命令:arp | wc -l 以下是我的代码:

 private String runCommand(String cmd, String params) {
        CommandLine commandLine = new CommandLine(cmd);
        commandLine.addArguments(params);
        ByteArrayOutputStream stdout = new ByteArrayOutputStream();
        ByteArrayOutputStream stderr = new ByteArrayOutputStream();
        PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdout, stderr);
        ExecuteWatchdog watchdog = new ExecuteWatchdog(30000);  // 30s timeout
        DefaultExecutor executor = new DefaultExecutor();
        executor.setStreamHandler(pumpStreamHandler);
        executor.setWatchdog(watchdog);

        try {
            int retCode = executor.execute(commandLine);
            System.out.println("Executed '" + cmd + "'\n"
                    + "returnCode: " + retCode + "\n"
                    + "stdout:\n" + stdout.toString() + "\n"
                    + "stderr:\n" + stderr.toString());

            if (retCode == 0) {
                return stdout.toString();
            } else {
                throw new NonZeroExitStatusReturnedException(commandLine.toString(), retCode);
            }

        } catch (IOException e) {
            throw new RuntimeException("Could not run command "+ commandLine.toString(), e);
        }
}

这里的 cmd 是 /bin/sh,参数是 -c arp|wc-l 代码给出以下输出:

Executed '/bin/sh'
returnCode: 0
stdout:
       54       71       4321

stderr:
usage: arp [-n] [-i interface] hostname
       arp [-n] [-i interface] [-l] -a
       arp -d hostname [pub] [ifscope interface]
       arp -d [-i interface] -a
       arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]
       arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]
       arp -f filename

我有两个问题:
问题 1。我不明白为什么我的输出中有三个数字(54 71 4321)。不是应该只有一个数字吗?

问题 2。有没有更好的方法来使用 apache commons exec 运行相同的命令?

【问题讨论】:

    标签: java arp apache-commons-exec


    【解决方案1】:

    关于您的第二个问题,我构建了一个纯 Java 解决方案:

    /**
    Run command $cmd1 and pipe its STDOUT to $cmd2, just like executing:
    
    $ cmd1 | cmd2
    
    from a Linux shell
    */
    private String runCommand(String cmd1, String[] params1, 
                              String cmd2, String[] params2) {
    
        PipedOutputStream stdin = new PipedOutputStream();
        PipedInputStream stdout = new PipedInputStream();
        // - pipe STDOUT of first process to STDIN of second process
        stdin.connect(stdout);
    
        // - First process: arp
        CommandLine commandLine = new CommandLine(cmd1).addArgument(params1);
    
        DefaultExecutor executor = new DefaultExecutor();
        executor.setStreamHandler(new PumpStreamHandler(stdin));
        executor.execute(commandLine, new DefaultExecuteResultHandler());
    
        // - Second process: wc
        CommandLine commandLine2 = new CommandLine(cmd2).addArguments(params2);
    
        DefaultExecutor executor2 = new DefaultExecutor();
        executor2.setStreamHandler(new PumpStreamHandler(System.out, System.err,
                                                         stdout));
        executor2.execute(commandLine2, new DefaultExecuteResultHandler());
    }
    

    这省略了对管道('|')的需要,这将增强代码的可移植性和安全性(它使执行清理检查更容易)。

    【讨论】:

      【解决方案2】:

      仔细阅读文档后 - https://commons.apache.org/proper/commons-exec/apidocs/org/apache/commons/exec/CommandLine.html.
      这是问题2的答案:

      private String runCommand(String cmd, String[] params) {
              CommandLine commandLine = new CommandLine(cmd);
              commandLine.addArguments(params, false);
              ByteArrayOutputStream stdout = new ByteArrayOutputStream();
              ByteArrayOutputStream stderr = new ByteArrayOutputStream();
              PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdout, stderr);
              ExecuteWatchdog watchdog = new ExecuteWatchdog(30000);  // 30s timeout
              DefaultExecutor executor = new DefaultExecutor();
              executor.setStreamHandler(pumpStreamHandler);
              executor.setWatchdog(watchdog);
      
              try {
                  int retCode = executor.execute(commandLine);
                  System.out.println("Executed '" + cmd + "'\n"
                          + "returnCode: " + retCode + "\n"
                          + "stdout:\n" + stdout.toString() + "\n"
                          + "stderr:\n" + stderr.toString());
      
                  if (retCode == 0) {
                      return stdout.toString();
                  } else {
                      throw new NonZeroExitStatusReturnedException(commandLine.toString(), retCode);
                  }
      
              } catch (IOException e) {
                  throw new RuntimeException("Could not run command "+ commandLine.toString(), e);
              }
      }
      

      这里的 cmd 是:/bin/sh 参数为:new String[] { "-c", "arp|wc -l" }

      【讨论】:

      • 如果你能注意到你的问题和你的解决方案代码之间的区别会很好:commandLine.addArgument(params, false); 因为否则很难得到区别。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 2018-05-15
      • 2017-01-22
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2017-02-05
      相关资源
      最近更新 更多