명령줄 인자 수락하기

Beginner

This tutorial is from open-source community. Access the source code

소개

**명령줄 인자 수락하기 (Accepting Command Line Arguments)**에 오신 것을 환영합니다. 이 랩은 Rust Book의 일부입니다. LabEx 에서 Rust 기술을 연습할 수 있습니다.

이 랩에서는 "minigrep"이라는 새 프로젝트를 생성하여 두 개의 명령줄 인자를 받습니다. 하나는 검색할 문자열이고, 다른 하나는 파일 경로입니다.

명령줄 인자 수락하기 (Accepting Command Line Arguments)

언제나 그렇듯이, cargo new를 사용하여 새 프로젝트를 생성해 봅시다. 프로젝트 이름을 minigrep으로 지정하여 시스템에 이미 있을 수 있는 grep 도구와 구별합니다.

$ cargo new minigrep
     Created binary (application) `minigrep` project
$ cd minigrep

첫 번째 작업은 minigrep이 두 개의 명령줄 인자를 받도록 만드는 것입니다: 파일 경로와 검색할 문자열입니다. 즉, 다음과 같이 cargo run과 함께 프로그램을 실행할 수 있기를 원합니다. 두 개의 하이픈은 다음 인자가 cargo가 아닌 우리 프로그램에 대한 것임을 나타내고, 검색할 문자열과 검색할 파일의 경로를 지정합니다.

cargo run -- searchstring example-filename.txt

현재, cargo new로 생성된 프로그램은 우리가 제공하는 인자를 처리할 수 없습니다. https://crates.io에 있는 몇몇 기존 라이브러리가 명령줄 인자를 받는 프로그램을 작성하는 데 도움이 될 수 있지만, 이 개념을 배우는 중이므로 직접 이 기능을 구현해 보겠습니다.

인자 값 읽기 (Reading the Argument Values)

minigrep이 전달된 명령줄 인자의 값을 읽을 수 있도록 하려면, Rust 표준 라이브러리에 제공된 std::env::args 함수가 필요합니다. 이 함수는 minigrep에 전달된 명령줄 인자의 이터레이터를 반환합니다. 이터레이터에 대해서는 13 장에서 자세히 다룰 것입니다. 지금은 이터레이터에 대해 두 가지 세부 사항만 알면 됩니다: 이터레이터는 일련의 값을 생성하고, 이터레이터에서 collect 메서드를 호출하여 이터레이터가 생성하는 모든 요소를 포함하는 벡터와 같은 컬렉션으로 변환할 수 있습니다.

Listing 12-1 의 코드는 minigrep 프로그램이 전달된 모든 명령줄 인자를 읽고, 값을 벡터로 수집할 수 있도록 합니다.

파일 이름: src/main.rs

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    dbg!(args);
}

Listing 12-1: 명령줄 인자를 벡터로 수집하고 출력하기

먼저 use 문을 사용하여 std::env 모듈을 범위 내로 가져와서 해당 args 함수를 사용할 수 있도록 합니다. std::env::args 함수가 두 단계의 모듈에 중첩되어 있음을 확인하십시오. 7 장에서 논의했듯이, 원하는 함수가 둘 이상의 모듈에 중첩된 경우, 함수 대신 상위 모듈을 범위 내로 가져오도록 선택했습니다. 이렇게 하면 std::env의 다른 함수를 쉽게 사용할 수 있습니다. 또한 use std::env::args를 추가한 다음 단순히 args로 함수를 호출하는 것보다 모호성이 적습니다. 왜냐하면 args는 현재 모듈에 정의된 함수로 쉽게 오해될 수 있기 때문입니다.

args 함수와 유효하지 않은 유니코드 (Invalid Unicode)

std::env::args는 인자에 유효하지 않은 유니코드가 포함된 경우 패닉 (panic) 할 것입니다. 프로그램이 유효하지 않은 유니코드를 포함하는 인자를 받아들여야 하는 경우, 대신 std::env::args_os를 사용하십시오. 해당 함수는 String 값 대신 OsString 값을 생성하는 이터레이터를 반환합니다. 여기서는 단순성을 위해 std::env::args를 사용하도록 선택했습니다. 왜냐하면 OsString 값은 플랫폼마다 다르며 String 값보다 작업하기 더 복잡하기 때문입니다.

main의 첫 번째 줄에서 env::args를 호출하고, 즉시 collect를 사용하여 이터레이터를 이터레이터가 생성한 모든 값을 포함하는 벡터로 변환합니다. collect 함수를 사용하여 다양한 종류의 컬렉션을 만들 수 있으므로, 문자열 벡터를 원한다는 것을 명시적으로 지정하기 위해 args의 타입을 주석 처리합니다. Rust 에서 타입을 주석 처리하는 경우는 매우 드물지만, collect는 Rust 가 원하는 컬렉션의 종류를 추론할 수 없기 때문에 종종 주석 처리가 필요한 함수 중 하나입니다.

마지막으로, 디버그 매크로를 사용하여 벡터를 출력합니다. 먼저 인자 없이 코드를 실행한 다음 두 개의 인자를 사용하여 실행해 보겠습니다.

$ cargo run
--snip--
[src/main.rs:5] args = [
"target/debug/minigrep",
]
$ cargo run -- needle haystack
--snip--
[src/main.rs:5] args = [
"target/debug/minigrep",
"needle",
"haystack",
]

벡터의 첫 번째 값은 "target/debug/minigrep"인데, 이는 바이너리의 이름입니다. 이는 C 의 인자 목록의 동작과 일치하며, 프로그램이 실행 시 호출된 이름을 사용할 수 있도록 합니다. 메시지를 출력하거나 프로그램이 호출된 명령줄 별칭에 따라 프로그램의 동작을 변경하려는 경우 프로그램 이름에 액세스하는 것이 편리합니다. 하지만 이 장의 목적을 위해, 우리는 이를 무시하고 필요한 두 개의 인자만 저장할 것입니다.

인자 값을 변수에 저장하기 (Saving the Argument Values in Variables)

프로그램은 현재 명령줄 인자로 지정된 값에 접근할 수 있습니다. 이제 두 인자의 값을 변수에 저장하여 프로그램의 나머지 부분에서 해당 값을 사용할 수 있도록 해야 합니다. Listing 12-2 에서 그렇게 합니다.

파일 이름: src/main.rs

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    let query = &args[1];
    let file_path = &args[2];

    println!("Searching for {}", query);
    println!("In file {}", file_path);
}

Listing 12-2: 검색어 인자와 파일 경로 인자를 저장할 변수 생성하기

벡터를 출력했을 때 보았듯이, 프로그램 이름은 args[0]에서 벡터의 첫 번째 값을 차지하므로, 인자를 인덱스 1 부터 시작합니다. minigrep이 받는 첫 번째 인자는 우리가 검색하려는 문자열이므로, 첫 번째 인자에 대한 참조를 변수 query에 넣습니다. 두 번째 인자는 파일 경로가 되므로, 두 번째 인자에 대한 참조를 변수 file_path에 넣습니다.

코드가 의도한 대로 작동하는지 확인하기 위해, 이러한 변수의 값을 임시로 출력합니다. testsample.txt 인자를 사용하여 이 프로그램을 다시 실행해 보겠습니다.

$ cargo run -- test sample.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished dev [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt

훌륭합니다, 프로그램이 작동합니다! 필요한 인자 값들이 올바른 변수에 저장되고 있습니다. 나중에 사용자가 인자를 제공하지 않는 경우와 같은 특정 잠재적인 오류 상황을 처리하기 위해 몇 가지 오류 처리를 추가할 것입니다. 지금은 해당 상황을 무시하고 대신 파일 읽기 기능을 추가하는 작업을 진행하겠습니다.

요약 (Summary)

축하합니다! 명령줄 인자 수락 (Accepting Command Line Arguments) 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.