2014-10-17 2 views
2

Java 프로그램 내에서 셸 명령을 실행하려고하면 이상한 문제가 있습니다. 나는 다음과 같은 권장 코드를 사용하여 수행하는 방법을 설명 수천 개의 웹 사이트가 존재하기 때문에 :셸 명령이 실행되지 않았습니다.

public String executeShellCommand (String command) 
{ 
    try 
    { 
     StringBuffer sb = new StringBuffer(); 
     String line = ""; 

     Process p = Runtime.getRuntime().exec(command); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(
       p.getInputStream())); 
     while ((line = reader.readLine()) != null) 
      sb.append(line + "\n"); 
     p.waitFor(); 

     return sb.toString(); 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
    return null; 
} 

Acutally를, 내가 예를 ls -aF에 대한 실행하려고 할 때입니다 잘 작동하고 난 결과로 일부 출력을 얻을. 그러므로 나는 위의 코드가 원칙적으로 정확하다고 확신한다. 그러나, 나는 달리기를 원하고 출력으로 파일을 생성하는 또 다른 프로그램을 가지고있다. 위와 같은 방법으로 실행하고 싶지만 결코 실행되지 않으며 출력 파일도 생성되지 않습니다. 또한 나는 java에서 어떤 오류, 경고 또는 무엇이든을 얻지 않는다. 실제 command 인수 문자열을 복사하여 콘솔에 붙여 넣으면 쉘에서 직접 programm/명령을 실행해도 문제가 없으며 출력 파일이 생성됩니다. 그래서 내가이 방법으로 전달하는 명령도 정확합니다.

Java 내에서 셸 명령을 실행할 때주의해야 할 추가 사항이 있습니까?

업데이트 : 제안 사항에 따라 코드를 수정했습니다. 그러나 여전히 걸려 있습니다.

public String executeShellCommand(List<String> command, String logfile, boolean waitForProcess) { try { 
    ProcessBuilder pb = new ProcessBuilder(command); 
    System.out.println("pb.toString() = " + pb.toString()); 
    Process p = pb.start(); 
    System.out.println("2"); 
    BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream())); 
    BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream())); 
    System.out.println("3"); 
    StringBuilder errSb = new StringBuilder(); 
    StringBuilder outSb = new StringBuilder(); 
    String line; 
    System.out.println("4"); 
    while ((line = err.readLine()) != null) { // <--- code hangs here 
     errSb.append(line + "\n"); 
     System.out.println("errSb = " + errSb.toString()); 
    } 
    System.out.println("4a"); 
    while ((line = out.readLine()) != null) { 
     outSb.append(line + "\n"); 
     System.out.println("outSb = " + outSb.toString()); 
    } 

    System.out.println("5"); 

    if(waitForProcess) { 
     System.out.println("Wait for process"); 
     p.waitFor(); 
    } else { 
     System.out.println("Sleep 5000"); 
     Thread.sleep(5000); 
    } 
    System.out.println("6"); 
    //Log result to file 
    if(logfile != null) { 
     OutputStreamWriter outWriter = new OutputStreamWriter(new FileOutputStream(logfile)); 
     outWriter.write(errSb.toString()); 
     outWriter.close(); 
    } 
    return errSb.toString(); 
} catch(Exception e) { e.printStackTrace(); } return null; } 
+0

오류 스트림을 기록하고 프로세스의 종료 값을 출력 해보십시오. –

답변

1

명령이 stderr에 너무 많은 문자를 쓰면 차단됩니다. sdtout과 마찬가지로, Java는 파이프를 통해 stderr를 리디렉션하고, 파이프를 읽지 않으면 채워지거나 차단 될 수 있습니다 (파이프 크기는 아마도 256 바이트 미만입니다). 이를 피하려면 주 스레드가 Process.getInputStream()에서 읽는 중일 때 다른 스레드에서 Process.getErrorStream()을 읽어야합니다.

이를 방지하기위한 간단한 방법은 표준 출력과 표준 에러 모두에는 Process.getInputStream()

0

으로 병합되도록하는 대신 Runtime.exec의()와 ProcessBuilder.redirectErrorStream (참)의 ProcessBuilder를 클래스를 사용하는 것입니다 Process javadoc 당 :

일부 네이티브 플랫폼에 표준 입력 및 출력 스트림을위한 제한된 버퍼 크기를 제공하기 때문에, 즉시 입력 스트림을 작성 또는 서브 프로세스의 출력 스트림을 판독하지 않으면 서브 프로세스는 블록, 또는 교착 될 수 있습니다 .

p.waitFor()으로 전화하십시오. waitFor() documentation을 신중하게 읽으면 :

이 프로세스 개체가 나타내는 프로세스가 종료 될 때까지 현재 스레드를 대기시킵니다 (필요한 경우).

오류 스트림과 출력 스트림이 읽히지 않기 때문에 프로세스가 중단 될 때까지 기다리는 중입니다. Process 클래스를 통해 외부 프로그램을 호출 할 때

p.start(); 

BufferedReader err= new BufferedReader(new InputStreamReader(p.getErrorStream())); 
BufferedReader out = new BufferedReader(new InputStreamReader(p.getOutputStream())); 

StringBuilder errSb = new StringBuilder(); 
StringBuilder outSb = new Stringbuilder(); 

String line; 
while ((line = err.readLine()) != null) { 
    errSb.append(line); 
} 

while ((line = out.readLine()) != null) { 
    outSB.append(line); 
} 

int retCode = p.waitFor(); //0 for success 
System.out.println(retCode); 
System.err.println(errSB.toString()); 

당신은 항상 어디 프로세스를 다른 사람이 이상한 상황에서 자신을 찾을 수 있습니다, 오류 스트림을 읽어야 할 사람 : 당신이 무엇을해야

,이 스트림을 읽는 것입니다 영원히 걸려. (운영 체제, 다른 응용 프로그램 등이 다른 사람을 죽일 때까지).

1.5로

, ProcessBuilder.start :


은 또한 당신이 javadoc에 따라, 자바 1.5부터 시작하여, 외부 프로그램을 실행하기 위해 권장되는 방법되지 않습니다 Runtime.getRuntime()를 사용하는 것으로 나타났습니다()는 프로세스를 만드는 데 선호되는 방법입니다.

ProcessBuilder pb = new ProcessBuilder("ls" , "-aF"); 
Process p = pb.start(); 
+0

그건 내 문제를 해결하지 못합니다. 여전히 매달려 있습니다. 내 업데이트를 참조하십시오. – toom

+0

실행하려는 명령이 정확히 무엇입니까? 입력 스트림에서 내용을 읽어야하고 입력 스트림을 공급하지 않으면 다시 중단됩니다. 'while ((line = err.readLine())! = null) {errSb.append (line + "\ n"); System.out.println ("errSb ="+ errSb.toString()); }'콘솔에 아무것도 인쇄하지 않습니까? – Daniel

+0

아니, 정확히 :'err.readLine()'에 매달린다. 내 명령은 데몬을 시작합니다. readline stuff의 주석 처리를 제거 할 때 아무런 문제없이 명령이 실행됩니다. – toom

관련 문제