java 리눅스 윈도우 명령어 실행 / command line executor / cmd

 

 

 

java 에서 리눅스 터미널 또는 윈도우 cmd 창에서 명령어를 실행시키는 방법이다.

 

 

java.lang.Process 클래스를 이용할 것이며

 

Process 클래스를 획득하기 위해서는 java.lang.Runtime 클래스 또는 java.lang.ProcessBuilder 클래스를 활용해야 하는데

 

본문에서는 Runtime 클래스를 활용한다.

 



 

소스 설명은 주석으로 대체한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class CommandLineExecutor {
 
    public static void main(String[] args) {
        // 실행
        CommandLineExecutor.execute("ipconfig");
    }
 
    /**
     * cmd 명령어 실행
     *
     * @param cmd
     */
    public static void execute(String cmd) {
        Process process = null;
        Runtime runtime = Runtime.getRuntime();
        StringBuffer successOutput = new StringBuffer(); // 성공 스트링 버퍼
        StringBuffer errorOutput = new StringBuffer(); // 오류 스트링 버퍼
        BufferedReader successBufferReader = null// 성공 버퍼
        BufferedReader errorBufferReader = null// 오류 버퍼
        String msg = null// 메시지
 
        List<String> cmdList = new ArrayList<String>();
 
        // 운영체제 구분 (window, window 가 아니면 무조건 linux 로 판단)
        if (System.getProperty("os.name").indexOf("Windows"> -1) {
            cmdList.add("cmd");
            cmdList.add("/c");
        } else {
            cmdList.add("/bin/sh");
            cmdList.add("-c");
        }
        // 명령어 셋팅
        cmdList.add(cmd);
        String[] array = cmdList.toArray(new String[cmdList.size()]);
 
        try {
 
            // 명령어 실행
            process = runtime.exec(array);
 
            // shell 실행이 정상 동작했을 경우
            successBufferReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "EUC-KR"));
 
            while ((msg = successBufferReader.readLine()) != null) {
                successOutput.append(msg + System.getProperty("line.separator"));
            }
 
            // shell 실행시 에러가 발생했을 경우
            errorBufferReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "EUC-KR"));
            while ((msg = errorBufferReader.readLine()) != null) {
                errorOutput.append(msg + System.getProperty("line.separator"));
            }
 
            // 프로세스의 수행이 끝날때까지 대기
            process.waitFor();
 
            // shell 실행이 정상 종료되었을 경우
            if (process.exitValue() == 0) {
                System.out.println("성공");
                System.out.println(successOutput.toString());
            } else {
                // shell 실행이 비정상 종료되었을 경우
                System.out.println("비정상 종료");
                System.out.println(successOutput.toString());
            }
 
            // shell 실행시 에러가 발생
            if (CommonUtil.notEmpty(errorOutput.toString())) {
                // shell 실행이 비정상 종료되었을 경우
                System.out.println("오류");
                System.out.println(successOutput.toString());
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                process.destroy();
                if (successBufferReader != null) successBufferReader.close();
                if (errorBufferReader != null) errorBufferReader.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }
 
}
cs

 

 



 

 

위 소스를 안정적으로 사용하기 위해서는 추가적인 이슈들을 해결해야 한다.

 

1. 한글이 깨지는 것에 유의해야 한다.

 

Stream으로 값을 꺼낼 때 encoding 타입을 적절하게 설정해야 한다.

 

2. command 명령어를 실행할 때 다소 위험한 명령어들은 필터링 할 필요가 있다.

 

예를들면 상황에 따라 다르겠지만 삭제 명령어나 OS를 수정할 수 있는 명령어 등은 막아야 한다.

 

3. 여러 명령어를 보내는 테스트 중에 오류가 아닌데 process.getErrorStream() 을 넘겨줄 때가 있었다.

 

오류라고 판단했는데 정상적으로 실행이 되는 경우가 있다.

 

테스트 하면서 나온 부분이고 위 내용들은 더 보완해야 할 것 같다.

 

by 개발자 CofS 2018.05.11 13:41
  • User 2018.09.22 14:33 신고 ADDR EDIT/DEL REPLY

    잘 보고 갑니다.
    그런데 finally에서 process를 destroy할 경우, 파일 스트림을 닫을 필요는 없지 않나요?

    • Favicon of http://cofs.tistory.com BlogIcon 개발자 CofS 2018.09.27 13:45 신고 EDIT/DEL

      안녕하세요 ㅎㅎ
      Process 객체를 kill 했을 경우 사용했던 스트림들이 반환되지는 않습니다.
      그래서 반환할 수 있도록 코드를 넣어두었습니다

      API 에서 Process 를 destory 했을 때 서브 프로세스를 종료한다고 하는데 이게 스트림의 반환까지인지는 잘 모르겠네요 ㅠㅠ