通过Runtime.exec()执行管道ps unix命令的问题

时间:2018-01-16 17:08:53

标签: java unix runtime.exec java-6

问题:

通过Runtime.exec(...)执行以下命令时,在查找匹配的引号字符时,它会因意外的EOF而失败。

一个奇怪的是,错误消息有一个严重的字符后跟两个单引号。

但是,当我执行通过putty在日志中打印出的命令时,它可以正常工作。

命令:

bin/sh -c 'ps -eo uname,pid,ppid,nlwp,pcpu,pmem,psr,start_time,tty,time,args | fgrep IAAPC | fgrep /f1/f2/a00-a/f3/server/server_1/env_1/javadriver | fgrep -v fgrep'

产生的错误:

-eo: -c: line 0: unexpected EOF while looking for matching `''
-eo: -c: line 1: syntax error: unexpected end of file

Java代码(Java 1.6 ......不要判断):

    String driverHome = trimToEmpty(System.getProperty("batchdriver.home"));
    String cmd = "/bin/sh -c 'ps -eo uname,pid,ppid,nlwp,pcpu,pmem,psr,start_time,tty,time,args | fgrep "+jobName+" | fgrep "+driverHome+" | fgrep -v fgrep'";
    String out = null, err = null;
    Process proc = null;
    try {
        proc = Runtime.getRuntime().exec(cmd);

        out = fullyRead(proc.getInputStream());
        err = fullyRead(proc.getErrorStream());

        int exitVal = proc.waitFor();

        if(logger.isDebugEnabled()) {
            logger.debug("Process Information: "+out);
        }
        if (isNotEmpty(err)) {
            logger.error(failedCommandMessage(cmd, out, err));
            this.processId = null;
            this.processDesc = PROCESS_NOT_FOUND;
            return;
        }

        String[] processes = StringUtils.split(out, "\r?\n");
        if (processes == null || processes.length == 0) {
            this.processDesc = PROCESS_NOT_FOUND;
        }
        else if (processes.length == 1) {
            String[] processInfo = processes[0].split("\\s+");
            this.processId = processInfo[1];
            if (!isNumeric(this.processId)) {
                this.processId = null;
            }
            this.processDesc = out;
        }
        else {
            this.processDesc = out;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Call to the OS completed with exit value: " + exitVal);
        }
    } catch (Exception e) {
        try {out = fullyRead(proc.getInputStream());} catch (Exception e1) {}
        try {err = fullyRead(proc.getErrorStream());} catch (Exception e1) {}
        this.processId = null;
        this.processDesc = PROCESS_NOT_FOUND;
        logger.error(failedCommandMessage(cmd, out, err), e);
    }

1 个答案:

答案 0 :(得分:2)

相关但不完全是:Pass a string with multiple contiguous spaces as a parameter to a jar file using Windows command prompt called from a java program

The Runtime.exec methods that take a String将其分解为令牌at whitespace only,因此这实际上运行程序/bin/sh(shell),其中包含以下参数:

 -c
 'ps
 -eo 
 uname,pid,ppid,nlwp,pcpu,pmem,psr,start_time,tty,time,args 
 |
 fgrep
 ...

shell解释这些参数:

 -c 'ps -- the script to run consists of the apostrophe character, p, s (and nothing more)
 -eo -- the name of the command being run is -eo 
 uname,pid,.... -- the first argument to the script is this
 | -- the second argument to the script is this
 fgrep -- the third argument to the script is this
 ... 
 -- but the script ignores the arguments and doesn't use them

因此你得到了

-eo: -c: unexpected EOF while looking for matching `''
# the script named -eo, with the option -c having value 'ps,
# tried to find a closing ' to match the opening ' and it's not there

这个shell显然是(GNU)bash;许多将数据字符串放在错误消息中的GNU程序用反引号和撇号包围它,因为这些是几十年前流行的ASCII解释中的匹配引号。

而是使用the String[] overload of exec为shell提供在shell 而不是StringTokenizer解析上面的命令行时获得的两个参数:

 String[] cmdary = {"/bin/sh", "-c", "ps -eo stuff | fgrep this | fgrep that | fgrep -v fgrep"};
 ... Runtime.getRuntime().exec(cmdary);

但是不是运行三个fgrep,而是运行ps并将输入流读取为行,并使用String.contains或类似方法在Java中测试它们。此外,您提出的大多数列ps都不会用于匹配的结果,这样只会浪费精力和杂乱。