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


104

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

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가 파이핑 및 리디렉션을 수행하도록하려면 어떻게해야합니까?


나는 다음과 같이 본다. 네이티브 자바 문자열 처리를 사용하면 자바 지원 플랫폼에 대한 자바 앱의 이식성이 보장된다. OTOH, 당신은 쉘 명령어와 함께 할 경우, langauge 변경하는 것이 더 쉽습니다 에서 자바,하지만 당신은 POSIX 플랫폼에있을 때에만 작동합니다. 앱이 실행되는 플랫폼보다 앱 언어를 변경하는 사람은 거의 없습니다. 그래서 당신의 추론이 조금 궁금하다고 생각합니다.
Janus Troelsen 2013

command | grep foo당신 과 같은 단순한 특정한 경우에는 command자바에서 기본적으로 필터링을 실행 하고 수행하는 것이 훨씬 낫습니다 . 코드가 다소 복잡해 지지만 전체 리소스 소비와 공격 표면이 크게 줄어 듭니다.
tripleee

답변:


182

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

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

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

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

@Kaj lsie 에 옵션을 추가하려면 어떻게해야 ls -lrt합니까?
kaustav datta 2013 년

8
@Kaj 셸에 명령 문자열을 지정하기 위해 -c를 사용하려고 시도하고 있지만 왜 이것을 단일 문자열 대신 문자열 배열로 만들어야 하는지를 이해하지 못합니다.
David Doria

2
누군가 android여기에서 버전을 찾고 있다면 /system/bin/sh대신 사용하십시오
Nexen

25

"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);
}

리디렉션과 동일한 동작, 즉 '>'문자가 표시됩니다. String 배열에 대한이 추가 분석은 깨달음을 얻었습니다
kris

바쁜 일정에서 하루를 보낼 필요가 없습니다. 눈앞에서 작성되었습니다. docs / api / java / lang / Runtime.html # exec (java.lang.String)
gpasch

6

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


1
메모리를 Java 프로세스의 주소 공간에 복사 한 다음 후속 프로세스로 다시 돌아 가기 때문에 이것이 os-native 파이프보다 훨씬 덜 효율적이라는 점을 지적 할 가치가 있습니다.
Tim Boudreau

0

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

String[] cmd = {
"cmd",
"/C",
"dir /B | findstr /R /C:"release""
};
Process p = Runtime.getRuntime().exec(cmd);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.