» Make grep CLI App in Rust » 2. Development » 2.2 Initial Version

Initial Version

src/lib.rs:

use std::fs::File;
use std::io::{self, BufRead};

use regex::Regex;

pub fn grep(pattern: &str, file_path: &str) -> io::Result<Vec<String>> {
    let regex = match Regex::new(pattern) {
        Ok(r) => r,
        Err(err) => return Err(io::Error::new(io::ErrorKind::InvalidInput, err)),
    };

    let file = File::open(file_path)?;
    let reader = io::BufReader::new(file);

    let mut matched_lines = Vec::new();
    for (_, line) in reader.lines().enumerate() {
        let line = line?;
        if regex.is_match(&line) {
            matched_lines.push(line.trim().to_string());
        }
    }
    Ok(matched_lines)
}

Crate regex provides support for regular expressions. Regular expressions (regex or regexp) are patterns that describe sets of strings.

Since regular expressions are not built directly into the Rust standard library, you need to add it as a dependency into the project.

Cargo.toml:

[package]
name = "lr_grustep"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
regex = "1.5"

Here, regex is the name of the crate, and 1.5 is the desired version. You can use different version constraints based on your requirements.

main.rs:

use std::env;

use lr_grustep::grep;

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

    if args.len() < 3 {
        eprintln!("Usage: {} <pattern> <file_path>", args[0]);
        std::process::exit(1);
    }

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

    match grep(pattern, file_path) {
        Ok(matched_lines) => {
            for line in matched_lines {
                println!("{}", line);
            }
        }
        Err(err) => {
            eprintln!("Error: {}", err);
        }
    }
}

Function std::env::args provides a convenient way to parse command-line arguments.

Run the program like this:

# search "line" in file main.rs
cargo run line src/main.rs

You will get result lines like below:

    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/lr_grustep line src/main.rs`
Ok(matched_lines) => {
for line in matched_lines {
println!("{}", line);

Note: Ignore the first two lines from cargo itself.