wc명령어는 줄,단어, 바이트 수를 알려주는 기본 명령어이다
1. 파생패턴을 이용해 명령줄 인수를 파싱을 한다.
// 파생패턴
#[derive(Debug,Parser)]
#[command(author,version,about)]
struct Args{
#[arg(value_name="FILE", default_value="-")]
// 연속된 문자열은 연속된 배열인 벡터에 담긴다
files:Vec<String>,
// 줄수
#[arg(short,long)]
lines:bool,
// 단어 수
#[arg(short,long)]
words:bool,
// 바이트 수
#[arg(short('c'),long)]
bytes:bool,
// 문자 수
#[arg(short('m'),long, conflicts_with("bytes"))]
chars:bool,
}
2. 파싱한 명령줄인수를 받아서 iter.all함수로 파일의 bool값을 테스트를 한다. 필드가 모두다 true라서 true반환, 그리고 wc에 명령에 대한 결과값을 출력한다.
// `iter.all()`을 이용해 값들이 모두 false인지 테스트하는 함수
// `args` 구조체의 필드 중 줄 수(`lines`), 단어 수(`words`), 바이트 수(`bytes`)가 모두 true인지 확인한다.
fn run(mut args: Args) -> Result<()> {
// `args`의 `lines`, `words`, `bytes`, `chars` 필드가 모두 true 인지 확인.
if [args.lines, args.words, args.bytes, args.chars].iter()
. all(|v| v == &false)
{
// 모든 필드가 true라 true
args.lines = true;
args.words = true;
args.bytes = true;
}
// 총합을 계산하기 위한 변수들 초기화
let mut total_lines = 0;
let mut total_words = 0;
let mut total_bytes = 0;
let mut total_chars = 0;
// 파일 목록에 대해 반복하며 총합 계산
for filename in &args.files {
match open(filename) {
Err(err) => eprintln!("{filename}:{err}"), // 파일 열기 오류 처리
Ok(file) => {
let info = count(file)?; // 파일의 줄 수, 단어 수, 바이트 수, 문자 수를 계산
// 결과를 형식화하여 출력
println!(
"{}{}{}{}{}",
format_field(info.num_lines, args.lines),
format_field(info.num_words, args.words),
format_field(info.num_bytes, args.bytes),
format_field(info.num_chars, args.chars),
if filename.as_str() == "-" {
"".to_string()
} else {
format!(" {}", filename)
}
);
// 총합 계산
total_lines += info.num_lines;
total_words += info.num_words;
total_bytes += info.num_bytes;
total_chars += info.num_chars;
}
}
}
// 파일이 여러 개일 경우, 총합 결과를 출력
if args.files.len() > 1 {
println!(
"{}{}{}{} total",
format_field(total_lines, args.lines),
format_field(total_words, args.words),
format_field(total_bytes, args.bytes),
format_field(total_chars, args.chars),
)
}
Ok(())
}
2-1. 파일을 읽기위해 무한 loop를 사용한다.
fn count(mut file: impl BufRead) -> Result<FileInfo> {
let mut num_lines = 0;
let mut num_words = 0;
let mut num_bytes = 0;
let mut num_chars = 0;
let mut line = String::new();
loop {
//read_line함수를 통해 파일 라인 한줄씩 읽고 바이트 수 반환
let line_bytes = file.read_line(&mut line)?;
// 0바이트이면 끝에 닿은것이므로 종료
if line_bytes == 0 {
break;
}
num_bytes += line_bytes;
num_lines += 1;
// 공백을 제외시키고 단어수를 센다
num_words += line.split_whitespace().count();
num_chars += line.chars().count();
// line 버퍼를 비운다
line.clear();
}
Ok(FileInfo {
num_lines,
num_words,
num_bytes,
num_chars,
})
}
3. 명령창에서 입력이 "-"가 포함된 명령을 읽고 그렇지 않을 때는 Buffreader로 파일을 열어 한줄씩 읽어서 카운트 함수로 라인 수,단어 수,바이트 수를 계산한다
// 스마트 포인터인 Box를 넣어 힙 메모리에 저장
fn open(filename:&str) -> Result<Box<dyn BufRead>> {
match filename {
"-" => Ok(Box::new(BufReader::new(io::stdin()))),
_ => Ok(Box::new(BufReader::new(File::open(filename)?)))
}
}
4. 결과값
4-1. 각 열의 줄,단어,바이트수를 보여주고 총합계도 출력해준다.
4-2. 문자 수도 출력해준다.
참고한 책입니다
https://www.yes24.com/Product/Goods/128929260
'Rust' 카테고리의 다른 글
러스트 뮤텍스와 세마포어 (0) | 2024.08.16 |
---|---|
Bufreader read_line()으로 파일 한줄씩 읽고 바이트 반환, Cursor 로 Read 구현 (0) | 2024.08.16 |
Rust 아토믹(atomic)연산 스레드 (0) | 2024.02.04 |
Rust 스레드 파킹 (0) | 2024.02.04 |
Rust 스레드 조건 변수 대기와 알림 (0) | 2024.02.04 |