Support Pipes
In Unix-like operating systems (such as Linux and macOS), a pipe is a mechanism for interprocess communication (IPC) that allows the output of one process to be used as the input of another.
Pipes are represented by the |
symbol in shell commands. When you use a command like command1 | command2
, it means that the standard output of command1
is connected to the standard input of command2
.
For example:
cat file.txt | grep "pattern"
In this command, the content of file.txt
is piped as input to the grep
command, which searches for the specified pattern.
Modify src/main.rs to make file_path
argument optional:
@@ -8,7 +8,7 @@ fn main() {
.author("literank")
.about("A grep-like utility in Rust")
.arg(Arg::with_name("pattern").required(true).index(1).help("The pattern to search for"))
- .arg(Arg::with_name("file_path").required(true).index(2).help("The file to search in"))
+ .arg(Arg::with_name("file_path").required(false).index(2).help("The file to search in"))
.arg(Arg::with_name("count").short("c").long("count").help("Only a count of selected lines is written to standard output"))
.arg(Arg::with_name("ignore-case").short("i").long("ignore-case").help("Perform case-insensitive matching"))
.arg(Arg::with_name("line-number").short("n").long("line-number").help("Each output line is preceded by its relative line number in the file, starting at line 1"))
@@ -18,13 +18,13 @@ fn main() {
// Extract command-line arguments
let pattern = matches.value_of("pattern").unwrap();
- let file_path = matches.value_of("file_path").unwrap();
+ let file_path = matches.value_of("file_path").unwrap_or("");
let options = GrepOptions {
ignore_case: matches.is_present("ignore-case"),
invert_match: matches.is_present("invert-match"),
};
You cannot do a recursive search when there's no file paths, modify src/main.rs:
- let result = if matches.is_present("recursive") {
+ let result = if matches.is_present("recursive") && !file_path.is_empty() {
grep_recursive(pattern, file_path.as_ref(), &options)
} else {
grep(pattern, file_path.as_ref(), &options)
Read the content from standard input when file_path
is empty in src/lib.rs:
@@ -66,8 +66,12 @@ pub fn grep_recursive(
}
fn read_file_lines(file_path: &Path) -> Result<Vec<String>, io::Error> {
- let file = fs::File::open(file_path)?;
- let reader = io::BufReader::new(file);
+ let reader: Box<dyn BufRead> = if file_path.components().count() == 0 {
+ Box::new(io::BufReader::new(io::stdin()))
+ } else {
+ let file = fs::File::open(file_path)?;
+ Box::new(io::BufReader::new(file))
+ };
Ok(reader.lines().map_while(Result::ok).collect())
}
Now you can do this:
cat src/main.rs | cargo run -- -n line
Its result:
5: // Define command-line arguments using clap
12: .arg(Arg::with_name("count").short("c").long("count").help("Only a count of selected lines is written to standard output"))
14: .arg(Arg::with_name("line-number").short("n").long("line-number").help("Each output line is preceded by its relative line number in the file, starting at line 1"))
16: .arg(Arg::with_name("invert-match").short("v").long("invert-match").help("Selected lines are those not matching any of the specified patterns"))
19: // Extract command-line arguments
38: print_result(&result, matches.is_present("line-number"))
47: fn print_result(result: &MatchResult, show_line_number: bool) {
57: if show_line_number {
58: println!("{}: {}", item.line_number, item.line);
60: println!("{}", item.line);
After re-installation, your grustep
command supports pipes as well.
cat src/main.rs | grustep -n line
It produces the same result as above.