[java] Runtime.exec ()에서 파이프를 작동시키는 방법은 무엇입니까?

다음 코드를 고려하십시오.

String commandf = "ls /etc | grep release";

try {

    // Execute the command and wait for it to complete
    Process child = Runtime.getRuntime().exec(commandf);
    child.waitFor();

    // Print the first 16 bytes of its output
    InputStream i = child.getInputStream();
    byte[] b = new byte[16];
    i.read(b, 0, b.length);
    System.out.println(new String(b));

} catch (IOException e) {
    e.printStackTrace();
    System.exit(-1);
}

프로그램의 출력은 다음과 같습니다.

/etc:
adduser.co

물론 쉘에서 실행하면 예상대로 작동합니다.

poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release

인터넷은 파이프 동작이 크로스 플랫폼이 아니라는 사실 때문에 Java를 생산하는 Java 공장에서 일하는 똑똑한 사람들은 파이프가 작동한다고 보장 할 수 없다고 말합니다.

어떻게 할 수 있습니까?

나는 자바보다는 구축하여 내 분석을 모두 수행 않을거야 grep그리고 sed내가 언어를 변경하려는 경우, 나는 완전히 무 이동하지 그 언어, 내 구문 분석 코드를 다시 쓰기에 강제 할 것이기 때문에.

쉘 명령을 호출 할 때 Java가 파이핑 및 리디렉션을 수행하도록하려면 어떻게해야합니까?



답변

스크립트를 작성하고 별도의 명령 대신 스크립트를 실행하십시오.

파이프는 셸의 일부이므로 다음과 같이 할 수도 있습니다.

String[] cmd = {
"/bin/sh",
"-c",
"ls /etc | grep release"
};

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


답변

“ps -ef | grep someprocess”라는 점을 제외하고는 Linux에서도 비슷한 문제가 발생했습니다.
적어도 “ls”를 사용하면 언어 독립적 인 (느리지 만) Java 대체가 있습니다. 예 :

File f = new File("C:\\");
String[] files = f.listFiles(new File("/home/tihamer"));
for (String file : files) {
    if (file.matches(.*some.*)) { System.out.println(file); }
}

“ps”를 사용하면 Java에 API가없는 것 같기 때문에 조금 더 어렵습니다.

Sigar가 우리를 도울 수 있다고 들었습니다 :
https://support.hyperic.com/display/SIGAR/Home

그러나 가장 간단한 해결책은 (Kaj가 지적한대로) 파이프 된 명령을 문자열 배열로 실행하는 것입니다. 다음은 전체 코드입니다.

try {
    String line;
    String[] cmd = { "/bin/sh", "-c", "ps -ef | grep export" };
    Process p = Runtime.getRuntime().exec(cmd);
    BufferedReader in =
            new BufferedReader(new InputStreamReader(p.getInputStream()));
    while ((line = in.readLine()) != null) {
        System.out.println(line);
    }
    in.close();
} catch (Exception ex) {
    ex.printStackTrace();
}

문자열 배열이 파이프와 함께 작동하는 이유는 단일 문자열이 작동하지 않는 반면 … 우주의 미스터리 중 하나입니다 (특히 소스 코드를 읽지 않은 경우). exec에 단일 문자열이 주어지면 먼저 구문 분석하기 때문이라고 생각합니다 (우리가 좋아하지 않는 방식으로). 반대로 exec에 문자열 배열이 주어지면 구문 분석하지 않고 단순히 운영 체제에 전달합니다.

사실, 바쁜 하루에 시간을내어 소스 코드 ( http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/)를 보면 Runtime.java # Runtime.exec % 28java.lang.String % 2Cjava.lang.String [] % 2Cjava.io.File % 29 ), 정확히 무슨 일이 일어나고 있는지 확인합니다.

public Process  [More ...] exec(String command, String[] envp, File dir)
          throws IOException {
    if (command.length() == 0)
        throw new IllegalArgumentException("Empty command");
    StringTokenizer st = new StringTokenizer(command);
    String[] cmdarray = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); i++)
        cmdarray[i] = st.nextToken();
    return exec(cmdarray, envp, dir);
}


답변

각 프로세스를 실행하는 런타임을 만듭니다. 첫 번째 런타임에서 OutputStream을 가져 와서 두 번째 런타임에서 InputStream으로 복사합니다.


답변

@Kaj 허용 답변은 Linux 용입니다. 이것은 Windows에 해당하는 것입니다.

String[] cmd = {
"cmd",
"/C",
"dir /B | findstr /R /C:"release""
};
Process p = Runtime.getRuntime().exec(cmd);


답변