Java exec()不返回管道连接命令的预期结果

时间:2021-01-27 00:11:46

I'm calling command line programs connected by pipes. All this works on Linux for sure.

我正在调用通过管道连接的命令行程序。所有这些都可以在Linux上运行。

My method:

protected String execCommand(String command) throws IOException {
    String line = null;
    if (command.length() > 0) {
        Process child = Runtime.getRuntime().exec(command);
        InputStream lsOut = child.getInputStream();
        InputStreamReader r = new InputStreamReader(lsOut);
        BufferedReader in = new BufferedReader(r);

        String readline = null;
        while ((readline = in.readLine()) != null) {
            line = line + readline;
        }
    }

    return line;
}

If I'm calling some cat file | grep asd, I'm getting the expected result. But not all commands works correctly. For example with this:

如果我正在调用一些猫文件| grep asd,我得到了预期的结果。但并非所有命令都能正常工作。例如:

cat /proc/cpuinfo | wc -l

or this:

cat /proc/cpuinfo | grep "model name" | head -n 1 | awk -F":" '{print substr($2, 2, length($2))}

the method will return null. I'm guessing this problem depends on output formatting commands like head, tail, wc, etc. How I can work around this problem and get the final result of the output?

该方法将返回null。我猜这个问题取决于输出格式化命令,如head,tail,wc等。我如何解决这个问题并获得输出的最终结果?

6 个解决方案

#1


8  

The pipe (like redirection, or >) is a function of the shell, and so execing directly from Java won't work. You need to do something like:

管道(如重定向或>)是shell的一个功能,因此直接从Java执行将不起作用。你需要做一些事情:

/bin/sh -c "your | piped | commands | here"

which executes a shell process with the command line (including pipes) specified after the -c (in quotes).

它使用在-c(引号)后指定的命令行(包括管道)执行shell进程。

Note also that you have to consume stdout and stderr concurrently, otherwise your spawned process will block waiting for your process to consume the output (or errors). More info here.

另请注意,您必须同时使用stdout和stderr,否则您生成的进程将阻止等待您的进程使用输出(或错误)。更多信息在这里。

#2


2  

Everyone who uses Runtime.exec should read this.

使用Runtime.exec的每个人都应该阅读此内容。

#3


2  

Still didn't found proper solution to execute piped commands with Runtime.exec, but found a workaround. I've simply wrote these scripts to separate bash files. Then Runtime.exec calls these bash scripts and gets expected result.

仍未找到使用Runtime.exec执行管道命令的正确解决方案,但找到了解决方法。我只是编写这些脚本来分隔bash文件。然后Runtime.exec调用这些bash脚本并获得预期的结果。

#4


1  

It might be a good idea to check the error stream of the Process as well.

检查Process的错误流也许是一个好主意。

#5


0  

The quick-and-dirty thing to do would be:

快速而肮脏的事情将是:

command = "/bin/sh -c '" + command.replaceAll("'", "'\''") + "'"

Normally, you'll have to watch out for shell injection (i.e. someone sneaks "; rm -rf /;" into the command). But that's only an issue if part of the command can be supplied from some other user input.

通常情况下,你必须注意shell注入(即有人偷偷摸摸“; rm -rf /;”进入命令)。但是,如果可以从其他一些用户输入提供部分命令,那么这只是一个问题。

The slow and painful approach would be to do the Bash piping yourself in Java. If you go down this road, you'll find out all the wonderful things that Bash gives you that's not directly available from Process.exec (pipes, redirection, compound commands, variable expansion, arithmetic evaluation, ...).

缓慢而痛苦的方法是用Java自己做Bash管道。如果你沿着这条路走下去,你会发现Bash给你的所有美妙的东西,不能直接从Process.exec获得(管道,重定向,复合命令,变量扩展,算术评估......)。

  1. Parse the command for | characters. Be sure to watch out for || and quoted strings.
  2. 解析|的命令字符。一定要注意||和引用的字符串。

  3. Spawn a new Process for every piped command.
  4. 为每个管道命令生成一个新进程。

  5. Create Threads that read the output from one command and write it to the input of the next command.
  6. 创建从一个命令读取输出的线程,并将其写入下一个命令的输入。

#6


0  

Probably a little too late but for others looking for a solution, try this...

可能有点太晚了但是对于寻找解决方案的其他人来说,试试这个......

String[] cmd = {
                        "/bin/sh",
                        "-c",
                        "cat /proc/cpuinfo | wc -l"
                    };

Process process = Runtime.getRuntime().exec(cmd);

All the best..

祝一切顺利..

#1


8  

The pipe (like redirection, or >) is a function of the shell, and so execing directly from Java won't work. You need to do something like:

管道(如重定向或>)是shell的一个功能,因此直接从Java执行将不起作用。你需要做一些事情:

/bin/sh -c "your | piped | commands | here"

which executes a shell process with the command line (including pipes) specified after the -c (in quotes).

它使用在-c(引号)后指定的命令行(包括管道)执行shell进程。

Note also that you have to consume stdout and stderr concurrently, otherwise your spawned process will block waiting for your process to consume the output (or errors). More info here.

另请注意,您必须同时使用stdout和stderr,否则您生成的进程将阻止等待您的进程使用输出(或错误)。更多信息在这里。

#2


2  

Everyone who uses Runtime.exec should read this.

使用Runtime.exec的每个人都应该阅读此内容。

#3


2  

Still didn't found proper solution to execute piped commands with Runtime.exec, but found a workaround. I've simply wrote these scripts to separate bash files. Then Runtime.exec calls these bash scripts and gets expected result.

仍未找到使用Runtime.exec执行管道命令的正确解决方案,但找到了解决方法。我只是编写这些脚本来分隔bash文件。然后Runtime.exec调用这些bash脚本并获得预期的结果。

#4


1  

It might be a good idea to check the error stream of the Process as well.

检查Process的错误流也许是一个好主意。

#5


0  

The quick-and-dirty thing to do would be:

快速而肮脏的事情将是:

command = "/bin/sh -c '" + command.replaceAll("'", "'\''") + "'"

Normally, you'll have to watch out for shell injection (i.e. someone sneaks "; rm -rf /;" into the command). But that's only an issue if part of the command can be supplied from some other user input.

通常情况下,你必须注意shell注入(即有人偷偷摸摸“; rm -rf /;”进入命令)。但是,如果可以从其他一些用户输入提供部分命令,那么这只是一个问题。

The slow and painful approach would be to do the Bash piping yourself in Java. If you go down this road, you'll find out all the wonderful things that Bash gives you that's not directly available from Process.exec (pipes, redirection, compound commands, variable expansion, arithmetic evaluation, ...).

缓慢而痛苦的方法是用Java自己做Bash管道。如果你沿着这条路走下去,你会发现Bash给你的所有美妙的东西,不能直接从Process.exec获得(管道,重定向,复合命令,变量扩展,算术评估......)。

  1. Parse the command for | characters. Be sure to watch out for || and quoted strings.
  2. 解析|的命令字符。一定要注意||和引用的字符串。

  3. Spawn a new Process for every piped command.
  4. 为每个管道命令生成一个新进程。

  5. Create Threads that read the output from one command and write it to the input of the next command.
  6. 创建从一个命令读取输出的线程,并将其写入下一个命令的输入。

#6


0  

Probably a little too late but for others looking for a solution, try this...

可能有点太晚了但是对于寻找解决方案的其他人来说,试试这个......

String[] cmd = {
                        "/bin/sh",
                        "-c",
                        "cat /proc/cpuinfo | wc -l"
                    };

Process process = Runtime.getRuntime().exec(cmd);

All the best..

祝一切顺利..