使用apache commons exec运行管道命令的更好方法

问题描述 投票:2回答:2

我正在使用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,params是-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
2个回答
1
投票

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

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 params是:new String[] { "-c", "arp|wc -l" }


0
投票

关于第二个问题,我构建了一个纯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());
}

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

© www.soinside.com 2019 - 2024. All rights reserved.