쉘(Shell)이란
쉘 명령어는 쉽게 말해 컴퓨터에 특정 작업을 수행하라고 지시하는 명령어입니다. 마치 우리가 다른 사람에게 "문 좀 닫아줘."라고 말하는 것과 비슷하게, 쉘 명령어를 통해 컴퓨터에게 파일을 복사하거나, 프로그램을 실행하거나, 시스템 정보를 확인하는 등 다양한 작업을 시킬 수 있습니다.
Window에서는 Powershell을 활용하고 Mac에서는 Terminal을 활용하여 Shell command를 실행할 수 있다. Shell command를 더 복잡하고 체계적으로 사용하기 위해 Shell script파일을 작성하고 실행 시킬 수 있다. 다만 Shell script는 Java가 가지는 다양한 기능들을 제공하지 않기에 Java언어로 복잡한 로직을 구성하고 Shell command가 필요한 부분만 따로 호출한다면 호율적이고 체계적으로 Shell command를 활용할 수 있을 것이다
ProcessBuilder
Java는 ProcessBuilder클래스를 제공한다. ProcessBuilder클래스를 사용하여 Shell command를 실행할 수 있다!
String command = "ps -ef | grep java" // java관련 프로세스를 찾는 Shell command
String[] bashCmd = new String[]{"/bin/bash", "-c", command}; // 운영체제가 Mac/Linux일 때
String[] WindowsCmd = new String[]{"cmd.exe", "/c", command} // 운영체제가 Windows일 때
ProcessBuilder processBuilder = new ProcessBuilder(bashCmd); // ProcessBuilder 생성
Process process = processBuilder.start(); // Shell command 실행 시작
Shell command 실행하고 작업이 끝날 때 까지 기다릴 수 있다. 결과 값을 받는게 필요한 작업이라면 아래와 같이 waitFor 함수를 써서 기다릴 수 있다.
boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
if (!finished) {
process.destroy();
throw new IOException("Timeout: Command execution exceeded " + timeout + " seconds.");
}
실행된 Shell command 작업에 대해서 output(결과), error(에러 메시지), exitCode(종료 코드)를 얻을 수 있고, 이를 응용할 수도 있다
String output = readStream(process.getInputStream());
String error = readStream(process.getErrorStream());
int exitCode = process.exitValue();
Shell 명령 실행 모듈
아래와 같이 Shell command 관련 명령을 수행할 수 있는 Util 클래스로 구성하여 사용하면 편리하게 사용할 수 있다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
public class ShellExecutor {
// main함수 내부 처럼 사용하면 된다.
public static void main(String[] args) {
try {
ExecutionResult result = executeShellCommand("echo Hello, World!", 5);
System.out.println("Output: " + result.getOutput());
System.out.println("Error: " + result.getError());
System.out.println("Exit Code: " + result.getExitCode());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
public static ExecutionResult executeShellCommand(String command, int timeout) throws IOException, InterruptedException {
String osType = getCommandForOS();
String[] cmd = osType.equals("Windows") ? new String[]{"cmd.exe", "/c", command} : new String[]{"/bin/bash", "-c", command};
ProcessBuilder processBuilder = new ProcessBuilder(cmd);
Process process = processBuilder.start();
String output = readStream(process.getInputStream());
String error = readStream(process.getErrorStream());
boolean finished = process.waitFor(timeout, TimeUnit.SECONDS);
if (!finished) {
process.destroy();
throw new IOException("Timeout: Command execution exceeded " + timeout + " seconds.");
}
int exitCode = process.exitValue();
return new ExecutionResult(output, error, exitCode);
}
private static String getCommandForOS() {
String os = System.getProperty("os.name").toLowerCase();
return os.contains("win") ? "Windows" : "Unix";
}
private static String readStream(InputStream stream) throws IOException {
StringBuilder output = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
reader.lines().forEach(line -> output.append(line).append("\n"));
}
return output.toString().trim();
}
public static class ExecutionResult {
private final String output;
private final String error;
private final int exitCode;
public ExecutionResult(String output, String error, int exitCode) {
this.output = output;
this.error = error;
this.exitCode = exitCode;
}
public String getOutput() {
return output;
}
public String getError() {
return error;
}
public int getExitCode() {
return exitCode;
}
}
}
1. import
- java.io.BufferedReader: 입력 스트림에서 줄별로 텍스트를 읽는 데 사용됩니다.
- java.io.IOException: 입출력 작업 중 오류가 발생하면 예외가 발생합니다.
- java.io.InputStream: 소스에서 나오는 바이트 스트림을 나타냅니다.
- java.io.InputStreamReader: InputStream의 바이트를 문자로 변환합니다.
- java.util.concurrent.TimeUnit: 시간 단위를 다루기 위한 유틸리티 클래스.
2. executeShellCommand
셸 명령 문자열과 시간 초과 값을 인수로 사용하여 객체를 반환합니다 ExecutionResult
- 먼저, 다음 getCommandForOS방법을 사용하여 운영 체제(Windows 또는 Unix)를 확인합니다.
- OS에 따라 명령 배열을 구축합니다.
- Windows: ["cmd.exe ", "/c", command] (cmd.exe를 사용하여 명령을 실행합니다 )
- Unix: ["/bin/bash", "-c", command] (bash를 사용하여 명령을 실행합니다)
- 구성된 명령 배열로 객체를 생성합니다 .ProcessBuilder
- .을 사용하여 프로세스를 시작합니다 processBuilder.start().
- 이 메서드를 사용하여 프로세스의 출력과 오류 스트림을 읽습니다 readStream.
- .을 사용하여 지정된 시간 내에 프로세스가 완료될 때까지 기다립니다 process.waitFor(timeout, TimeUnit.SECONDS).
- 프로세스가 제한 시간 내에 완료되지 않으면 .을 사용하여 해당 프로세스를 파괴 process.destroy()하고 throw합니다 IOException.
- process.exitValue() 종료 코드를 검색합니다
- 마지막으로 출력, 오류 메시지, 종료 코드를 포함하는 객체를 반환합니다 .ExecutionResult
3. getCommandForOS
운영 체제 이름을 검색하여 "win"이 포함되어 있으면 "Windows"를 반환하고, 그렇지 않으면 "Unix"를 반환합니다.
4. readStream
입력 스트림에서 데이터를 읽고 문자열 표현을 반환합니다.
- 출력을 축적하기 위해 StringBuilder를 생성합니다 .
- try-with-resources 블록을 사용해 객체를 자동으로 닫습니다 BufferedReader.
- BufferedReader.lines() 을 사용하여 입력 스트림을 줄별로 읽습니다 .
- 각 줄을 줄바꿈 문자로 추가합니다
- 마지막으로, 누적된 출력의 잘린 문자열 표현을 반환합니다
'STUDY > JAVA' 카테고리의 다른 글
[Java] 바이트 크기를 사람이 읽기 편한 형식으로 변환 (kb, mb, gb ...) (0) | 2024.10.14 |
---|---|
[JAVA] jdk 2개 이상 설정 방법 (java 버전 여러개 사용하기) (0) | 2024.10.11 |
[JAVA] java.io 패키지 - 스트림으로 배우는 자바 입출력 (0) | 2024.07.31 |
[JAVA] 자바 파일 권한 변경 방법 (0) | 2024.07.30 |
[Java] 기본형 매개변수, 참조형 매개변수, 참조형 반환값 (1) | 2024.06.10 |