Why does my Java code execute bash command incorrectly?

别说谁变了你拦得住时间么 提交于 2019-12-23 21:24:06

问题


I am trying to make my Java program interact with Linux bash but something goes wrong. I have a simple executable prog that reads the one integer from stdin and outputs its square. Executing

echo 5 | ./prog

from bash itself prints correct answer 25 in stdout but running

import java.io.*;

public class Main {
    public static void main(String[] args) throws InterruptedException, IOException {
        Runtime run = Runtime.getRuntime();
        Process proc = run.exec("echo 5 | ./prog");
        proc.waitFor();
        BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        while(br.ready())
            System.out.println(br.readLine());
    }
}

unexpectedly gives 5 | ./prog. What is the solution?


回答1:


Java exec cannot run shell commands like that. If you want to run a shell command, you need to explicitly invoke the shell; e.g.

Process proc = run.exec(new String[]{"/bin/sh", "-c", "echo 5 | ./prog"});

For more details on what Java does with this, read the javadocs for exec(String) and exec(String[]). Note that these are "convenience methods", and you need to follow the chain of links to the underlying methods for a complete understanding of what the javadoc is saying.

If you want even more detail on how Java handles this, there is the source code ...

If you want to understand in depth why Java doesn't handle the shell syntax itself, you probably need to take a deep dive into the architecture and philosophy of UNIX / Linux systems, and the separation of concerns between application, operating system and command shell. Note that there are a myriad different shells, each with (potentially) different rules for quoting, argument splitting, redirection, pipes, etcetera. Most of the popular shells are similar, but that's just the way things panned out.

Explanation of the solution:

  • The reason for splitting the command by hand is that exec(String) won't split the command into a single command and arguments correctly. It can't. This is an example where there are two commands in a pipeline.

  • The reason for using "sh" is ... well ... you need a shell to parse and process a shell command line. Java's exec command does not support shell syntax ... as the javadoc explains.

  • The purpose of the "-c" option is explained by "man sh". Basically, sh -c "a b c" means "use 'sh' to run the command line 'a b c'".

FWIW, it is technically possible to construct and run a pipeline solely in Java (i.e. without relying on an external shell), but it is generally not worth the effort. You've already introduced a platform dependency by running external commands, so an extra dependency in the form of a specific shell command and syntax doesn't make things significantly worse.



来源:https://stackoverflow.com/questions/18424541/why-does-my-java-code-execute-bash-command-incorrectly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!