rust 에서 std::process::Command 를 사용해 cmd 명령이나 파일을 실행 할 수 있는데, 어떤 객체들이 사용되는지 대략적으로 살펴본다.
use
use std::error::Error as StdError;
use std::fmt;
use std::io::Read;
use std::os::windows::process::CommandExt; // creation flag
use std::process::{self, Command, Stdio, ExitStatus};
use std::env;
use std::path::Path;
호출 결과 구조체
struct ProcessResult {
stdout: Vec<u8>,
stderr: Vec<u8>,
exit_status: ExitStatus,
}
에러처리
io 에러에 대해서만 처리해 준다.
#[derive(Debug)]
enum Error{
Io(std::io::Error),
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::Io(err)
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Io(err) => Some(err),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(err) => write!(f, "io error: {}", err),
}
}
}
명령 호출 함수
프로그램명과 arguments를 입력받아 명령을 호출한다. 표춘출력과 표준에러, 파라미터 목록 전달 후 spawn() 을 호출해 준다. 실행할 프로그램이 없는 경우와 같은 io 에러의 경우 spawn() 에서 발생하며, '?' 를 통해 에러를 그대로 리턴하게 된다.
표준에러의 경우 정상 수행은 되었지만 프로그램의 에러(파라미터 부족 등)의 경우이므로, 정상적인 ProcessResult로 리턴하게 된다.
fn run_process(program: String, args: &Vec<String>) -> Result<ProcessResult, Error> {
let mut child = Command::new(program)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.args(args)
.spawn()?;
let mut stdout = vec![];
let child_stdout = child.stdout.take();
std::io::copy(&mut child_stdout.unwrap(), &mut stdout)?;
let exit_status = child.wait()?;
let mut stderr = vec![];
if let Some(mut reader) = child.stderr {
reader.read_to_end(&mut stderr)?;
}
Ok(ProcessResult {
stdout,
stderr,
exit_status,
})
}
프로세스 실행 및 결과 출력
env::args() 로 프로그램 실행시 인자 목록을 가져올 수 있는데, collect() 를 통해 Vec<String> 으로 변환한다.
각 인자 목록 중 0번 째는 현재 실행하는 파일이므로, 1 번째를 실행할 프로그램, 2번 부터 파라미터로 구분해 저장한다.
fn main() {
println!("Hello, world!");
let args: Vec<String> = env::args().collect();
let program = args[1].clone();
let params: Vec<String> = args[2..].to_vec();
// 프로세스 실행
// io 에러발생 시 에러 출력 후 종료, 종료 시 exit code 1
let result = run_process(program, ¶ms).unwrap_or_else(|err| {
println!("io error: {:?}", err);
process::exit(1);
});
// 정상 종료
// exit code 에 따라 표준출력이나 표준에러 확인
if result.exit_status.success() {
let stdout = std::str::from_utf8(&result.stdout).expect("invalid output");
println!("result: {}", stdout);
} else {
let stderr = String::from_utf8(result.stderr).unwrap_or_default();
println!("error: {}\n{}",result.exit_status, stderr);
}
}
테스트
cargo build
.\target\debug\sample.exe java --version
'프로그래밍 > RUST' 카테고리의 다른 글
[RUST] https 를 통해 파일 다운로드 간단 샘플 (0) | 2024.06.20 |
---|---|
[RUST] 다른 언어와 다른 부분, 특징 정리 중.... (0) | 2024.06.18 |
[RUST] cargo 기본 사용법 (0) | 2024.05.14 |