Java Runtime.getRuntime () : 명령 행 프로그램 실행에서 출력 얻기


155

런타임을 사용하여 Java 프로그램에서 명령 프롬프트 명령을 실행하고 있습니다. 그러나 명령이 반환하는 출력을 얻는 방법을 알지 못합니다.

내 코드는 다음과 같습니다.

Runtime rt = Runtime.getRuntime();

String[] commands = {"system.exe", "-send" , argument};

Process proc = rt.exec(commands);

나는 노력 System.out.println(proc);했지만 아무것도 반환하지 않았다. 해당 명령을 실행하면 세미콜론으로 구분 된 두 개의 숫자가 반환되어야합니다. 이것을 변수로 인쇄하여 인쇄하려면 어떻게해야합니까?

다음은 현재 사용중인 코드입니다.

String[] commands = {"system.exe", "-get t"};

Process proc = rt.exec(commands);

InputStream stdIn = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(stdIn);
BufferedReader br = new BufferedReader(isr);

String line = null;
System.out.println("<OUTPUT>");

while ((line = br.readLine()) != null)
     System.out.println(line);

System.out.println("</OUTPUT>");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);

그러나 출력으로 아무것도 얻지 못하지만 해당 명령을 직접 실행할 때 정상적으로 작동합니다.

답변:


244

갈 길은 다음과 같습니다.

Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-get t"};
Process proc = rt.exec(commands);

BufferedReader stdInput = new BufferedReader(new 
     InputStreamReader(proc.getInputStream()));

BufferedReader stdError = new BufferedReader(new 
     InputStreamReader(proc.getErrorStream()));

// Read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
    System.out.println(s);
}

// Read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
    System.out.println(s);
}

자세한 내용은 여기 에서 Javadoc을 읽으 십시오 . ProcessBuilder사용하는 것이 좋습니다.


4
@AlbertChen pwd && ls은 단일 파일을 실행하는 것이 아니라 셸에서 파일을 실행할 때 /bin/pwd/bin/ls실행 파일을 모두 실행합니다. Java 내에서 이와 같은 작업을 수행하려면 다음과 같은 작업을 수행해야합니다 {"/bin/bash","-c", "pwd && ls"}. 더 이상 질문이 없을 수도 있지만 다른 사람들이 대답 할 수도 있다고 생각했습니다.
735 테슬라

3
두 스트림을 읽는 것은 동시에 일어나야한다고 생각합니다. 만약 여러분의 경우와 같이 stdStream의 출력이 버퍼를 채우면 오류 스트림을 읽을 수
없기 때문입니다

3
Li3ro는 부분적으로 옳습니다. 듣고있는 프로그램에는 제한된 버퍼 stdoutstderr출력이 있습니다. 동시에 듣지 않으면 다른 쪽을 읽는 동안 그 중 하나가 채워집니다. 당신이 듣고있는 프로그램은 채워진 버퍼에 쓰려고 시도하는 것을 막을 것이고, 다른 한편으로는 당신의 프로그램은 결코 반환하지 않는 버퍼에서 읽으려고 시도하는 것을 막을 것 EOF입니다. 당신은 해야한다 동시에 두 스트림에서 읽습니다.
Gili

1
@Gili 그렇다면 왜 Li3ro가 "부분적으로"옳습니까? Li3ro가 완벽하고 완전히 옳지 않습니까? 이 경우 2011 년 이후 왜 틀린 답이 여기에 걸려 있는지 그리고 왜 200 개가 넘는 공감대가 있는지 이해가되지 않습니다 ... 혼란 스럽습니다.
Andrey Tyukin

2
@AndreyTyukin 당신이 맞아요. 모든 현재 답변은 교착 상태에 취약합니다. 나는 다른 답변이 가시성을 얻을 수 있도록 그들을 하향 투표하는 것이 좋습니다. 귀하의 검토에 대한 새로운 답변을 게시했습니다 : stackoverflow.com/a/57949752/14731 . 잘만되면 나는 이것을 올바르게 얻었다.
Gili

68

더 빠른 방법은 다음과 같습니다.

public static String execCmd(String cmd) throws java.io.IOException {
    java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

이것은 기본적으로 요약 된 버전입니다.

public static String execCmd(String cmd) throws java.io.IOException {
    Process proc = Runtime.getRuntime().exec(cmd);
    java.io.InputStream is = proc.getInputStream();
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    String val = "";
    if (s.hasNext()) {
        val = s.next();
    }
    else {
        val = "";
    }
    return val;
}

나는이 질문이 오래되었다는 것을 알고 있지만 이것이 더 빠를 것이라고 생각하기 때문에이 답변을 게시하고 있습니다.


4
좋은 답변 주셔서 감사합니다. "\\ A"가 분리 문자 인 이유는 무엇입니까?
Gottfried

1
나는 원래 이것을 썼을 때 나의 논리가 무엇인지 완전히 기억하지 못한다. 나는이 솔루션을 잠시 동안 사용 해 왔지만 \A정규 표현식에서 문자열의 시작을 의미하고 슬래시를 피해야 했기 때문이라고 생각합니다 .
735 테슬라

5
"\ A"는 벨 문자입니다. "^"는 정규식에서 문자열의 시작이고 "$"는 정규식에서 문자열의 끝입니다. 이것은 당신이 보지 않을 것으로 예상되는 캐릭터입니다. Java 문서에 따르면 기본 구분 기호는 공백입니다. 이렇게하면 명령의 전체 결과가 나올 수 있습니다.
행크 슐츠

11

ProcessBuilder제안 된 Senthil을 사용 하는 것 외에도 , Runtime.exec ()가하지 않을 경우모든 권장 사항 을 읽고 구현 해야 합니다 .


해당 스 니펫은 표준 오류 스트림을 사용하지 않는 것 같습니다 (링크 된 기사에서 권장). 또한 ProcessBuilder현재 권장되는대로 두 번 사용하지 않습니다 . 를 사용 ProcessBuilder하면 출력 및 오류 스트림을 병합하여 한 번에 둘 다 쉽게 사용할 수 있습니다.
Andrew Thompson

11

classpath에서 이미 Apache commons-io를 사용할 수있는 경우 다음을 사용할 수 있습니다.

Process p = new ProcessBuilder("cat", "/etc/something").start();
String stderr = IOUtils.toString(p.getErrorStream(), Charset.defaultCharset());
String stdout = IOUtils.toString(p.getInputStream(), Charset.defaultCharset());

7

또한 명령 출력을 얻기 위해 스트림을 사용할 수 있습니다.

public static void main(String[] args) throws IOException {

        Runtime runtime = Runtime.getRuntime();
        String[] commands  = {"free", "-h"};
        Process process = runtime.exec(commands);

        BufferedReader lineReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        lineReader.lines().forEach(System.out::println);

        BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        errorReader.lines().forEach(System.out::println);
    }

7

@Senthil 및 @Arend 답변 ( https://stackoverflow.com/a/5711150/2268559 )이 언급되었습니다 ProcessBuilder. 다음은 ProcessBuilder명령에 환경 변수 및 작업 폴더 지정과 함께 사용하는 예입니다 .

    ProcessBuilder pb = new ProcessBuilder("ls", "-a", "-l");

    Map<String, String> env = pb.environment();
    // If you want clean environment, call env.clear() first
    //env.clear();
    env.put("VAR1", "myValue");
    env.remove("OTHERVAR");
    env.put("VAR2", env.get("VAR1") + "suffix");

    File workingFolder = new File("/home/user");
    pb.directory(workingFolder);

    Process proc = pb.start();

    BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));

    BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

    // Read the output from the command:
    System.out.println("Here is the standard output of the command:\n");
    String s = null;
    while ((s = stdInput.readLine()) != null)
        System.out.println(s);

    // Read any errors from the attempted command:
    System.out.println("Here is the standard error of the command (if any):\n");
    while ((s = stdError.readLine()) != null)
        System.out.println(s);

6

이 글을 쓰는 시점에서 코드를 포함한 다른 모든 답변은 교착 상태를 초래할 수 있습니다.

프로세스에는 제한된 버퍼 stdoutstderr출력이 있습니다. 동시에 듣지 않으면 다른 하나를 읽으려고 할 때 하나가 채워집니다. 예를 들어, stdout프로세스가에 쓰기를 기다리는 동안 읽기를 기다리고있을 수 있습니다 stderr. stdout버퍼가 비어 있어 버퍼 에서 읽을 수없고 프로세스 stderr가 가득 차서 버퍼에 쓸 수 없습니다 . 당신은 서로 영원히 기다리고 있습니다.

교착 상태의 위험없이 프로세스 출력을 읽는 가능한 방법은 다음과 같습니다.

public final class Processes
{
    private static final String NEWLINE = System.getProperty("line.separator");

    /**
     * @param command the command to run
     * @return the output of the command
     * @throws IOException if an I/O error occurs
     */
    public static String run(String... command) throws IOException
    {
        ProcessBuilder pb = new ProcessBuilder(command).redirectErrorStream(true);
        Process process = pb.start();
        StringBuilder result = new StringBuilder(80);
        try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())))
        {
            while (true)
            {
                String line = in.readLine();
                if (line == null)
                    break;
                result.append(line).append(NEWLINE);
            }
        }
        return result.toString();
    }

    /**
     * Prevent construction.
     */
    private Processes()
    {
    }
}

키는 사용하는 것입니다 ProcessBuilder.redirectErrorStream(true)리디렉션 stderrstdout스트림입니다. 따라서 stdout와 사이를 번갈아 가면서 단일 스트림을 읽을 수 있습니다 stderr. 이를 수동으로 구현 하려면 차단하지 않도록 두 개의 다른 스레드에서 스트림을 사용해야합니다.


오 와우! 나는 당신이 코멘트에 너무 빨리 대답 할 것이라고 기대하지 않았습니다. :) 나는 지금 현상금 시작을 고려하고 있습니다. 나중에 답변을 살펴볼 것입니다. 감사!
Andrey Tyukin

1

Kotlin에 글을 쓰면 다음을 사용할 수 있습니다.

val firstProcess = ProcessBuilder("echo","hello world").start()
val firstError = firstProcess.errorStream.readBytes().decodeToString()
val firstResult = firstProcess.inputStream.readBytes().decodeToString()

0

이전 답변에서 채택 :

public static String execCmdSync(String cmd, CmdExecResult callback) throws java.io.IOException, InterruptedException {
    RLog.i(TAG, "Running command:", cmd);

    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(cmd);

    //String[] commands = {"system.exe", "-get t"};

    BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
    BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

    StringBuffer stdOut = new StringBuffer();
    StringBuffer errOut = new StringBuffer();

    // Read the output from the command:
    System.out.println("Here is the standard output of the command:\n");
    String s = null;
    while ((s = stdInput.readLine()) != null) {
        System.out.println(s);
        stdOut.append(s);
    }

    // Read any errors from the attempted command:
    System.out.println("Here is the standard error of the command (if any):\n");
    while ((s = stdError.readLine()) != null) {
        System.out.println(s);
        errOut.append(s);
    }

    if (callback == null) {
        return stdInput.toString();
    }

    int exitVal = proc.waitFor();
    callback.onComplete(exitVal == 0, exitVal, errOut.toString(), stdOut.toString(), cmd);

    return stdInput.toString();
}

public interface CmdExecResult{
    void onComplete(boolean success, int exitVal, String error, String output, String originalCmd);
}

0

이 페이지의 다른 스 니펫 과 거의 동일 하지만 기능 을 통해 구성하는 것만으로 여기에갑니다 ...

String str=shell_exec("ls -l");

클래스 기능 :

public String shell_exec(String cmd)
       {
       String o=null;
       try
         {
         Process p=Runtime.getRuntime().exec(cmd);
         BufferedReader b=new BufferedReader(new InputStreamReader(p.getInputStream()));
         String r;
         while((r=b.readLine())!=null)o+=r;
         }catch(Exception e){o="error";}
       return o;
       }

-1

InputStream런타임을 읽으십시오 .

Runtime rt = Runtime.getRuntime();
String[] commands = {"system.exe", "-send", argument};
Process proc = rt.exec(commands);
BufferedReader br = new BufferedReader(
    new InputStreamReader(proc.getInputStream()));
String line;
while ((line = br.readLine()) != null)
    System.out.println(line);

proc.getErrorStream()프로세스가 오류 출력을 인쇄하는 경우 오류 스트림 ( ) 을 읽어야 할 수도 있습니다 . 를 사용하면 오류 스트림을 입력 스트림으로 리디렉션 할 수 있습니다 ProcessBuilder.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.