From 334488cab7709787ac1a7a0c6bfd4d3fd13b0cf7 Mon Sep 17 00:00:00 2001 From: Asha20 Date: Sat, 14 Aug 2021 17:57:01 +0200 Subject: [PATCH] Add -q/--quiet/--has-match flag (#813) Instead of printing to stdout, the program will return 1 as the exit code if there are no matches and 0 otherwise. --- CHANGELOG.md | 2 ++ doc/fd.1 | 7 +++++++ src/app.rs | 14 ++++++++++++++ src/exit_codes.rs | 4 +++- src/main.rs | 1 + src/options.rs | 4 ++++ src/walk.rs | 10 +++++++++- tests/tests.rs | 13 +++++++++++++ 8 files changed, 53 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8280b3..197c6ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Features - Don't buffer command output from `--exec` when using a single thread. See #522 +- Add new `-q, --quiet` flag, see #303 (@Asha20) + ## Bugfixes - Set default path separator to `/` in MSYS, see #537 and #730 (@aswild) diff --git a/doc/fd.1 b/doc/fd.1 index 3dfec2e..487ffd0 100644 --- a/doc/fd.1 +++ b/doc/fd.1 @@ -93,6 +93,13 @@ Limit the number of search results to 'count' and quit immediately. .B \-1 Limit the search to a single result and quit immediately. This is an alias for '--max-results=1'. .TP +.B \-q, \-\-quiet +When the flag is present, the program does not print anything and will instead exit with a code of 0 if there is at least one search result. +Otherwise, the exit code will be 1. +This is mainly for usage in scripts and can be faster than checking for output because the search can be stopped early after the first match. +.B \-\-has\-results +can be used as an alias. +.TP .B \-\-show-errors Enable the display of filesystem errors for situations such as insufficient permissions or dead symlinks. diff --git a/src/app.rs b/src/app.rs index 2d6ec94..7139e9d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -504,6 +504,20 @@ pub fn build_app() -> App<'static, 'static> { .long_help("Limit the search to a single result and quit immediately. \ This is an alias for '--max-results=1'.") ) + .arg( + Arg::with_name("quiet") + .long("quiet") + .short("q") + .alias("has-results") + .hidden_short_help(true) + .conflicts_with_all(&["exec", "exec-batch", "list-details", "max-results"]) + .long_help( + "When the flag is present, the program does not print anything and will \ + return with an exit code of 0 if there is at least one match. Otherwise, the \ + exit code will be 1. \ + '--has-results' can be used as an alias." + ) + ) .arg( Arg::with_name("show-errors") .long("show-errors") diff --git a/src/exit_codes.rs b/src/exit_codes.rs index 720440f..2083b32 100644 --- a/src/exit_codes.rs +++ b/src/exit_codes.rs @@ -1,6 +1,7 @@ #[derive(Debug, Clone, Copy, PartialEq)] pub enum ExitCode { Success, + HasResults(bool), GeneralError, KilledBySigint, } @@ -9,6 +10,7 @@ impl From for i32 { fn from(code: ExitCode) -> Self { match code { ExitCode::Success => 0, + ExitCode::HasResults(has_results) => !has_results as i32, ExitCode::GeneralError => 1, ExitCode::KilledBySigint => 130, } @@ -17,7 +19,7 @@ impl From for i32 { impl ExitCode { fn is_error(self) -> bool { - self != ExitCode::Success + i32::from(self) != 0 } } diff --git a/src/main.rs b/src/main.rs index 7acba88..f0ce9a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -346,6 +346,7 @@ fn run() -> Result { follow_links: matches.is_present("follow"), one_file_system: matches.is_present("one-file-system"), null_separator: matches.is_present("null_separator"), + quiet: matches.is_present("quiet"), max_depth: matches .value_of("max-depth") .or_else(|| matches.value_of("rg-depth")) diff --git a/src/options.rs b/src/options.rs index aa9b5ea..c17dd4d 100644 --- a/src/options.rs +++ b/src/options.rs @@ -54,6 +54,10 @@ pub struct Options { /// The number of threads to use. pub threads: usize, + /// If true, the program doesn't print anything and will instead return an exit code of 0 + /// if there's at least one match. Otherwise, the exit code will be 1. + pub quiet: bool, + /// Time to buffer results internally before streaming to the console. This is useful to /// provide a sorted output, in case the total execution time is shorter than /// `max_buffer_time`. diff --git a/src/walk.rs b/src/walk.rs index bcb15d4..a053278 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -233,6 +233,10 @@ fn spawn_receiver( for worker_result in rx { match worker_result { WorkerResult::Entry(value) => { + if config.quiet { + return ExitCode::HasResults(true); + } + match mode { ReceiverMode::Buffering => { buffer.push(value); @@ -286,7 +290,11 @@ fn spawn_receiver( } } - ExitCode::Success + if config.quiet { + ExitCode::HasResults(false) + } else { + ExitCode::Success + } } }) } diff --git a/tests/tests.rs b/tests/tests.rs index 0b6e6b5..724abe1 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1425,6 +1425,19 @@ fn test_exec_with_separator() { ); } +/// Non-zero exit code (--quiet) +#[test] +fn test_quiet() { + let dirs = &[]; + let files = &["a.foo", "b.foo"]; + let te = TestEnv::new(dirs, files); + + te.assert_output(&["-q"], ""); + te.assert_output(&["--quiet"], ""); + te.assert_output(&["--has-results"], ""); + te.assert_failure_with_error(&["--quiet", "c.foo"], "") +} + /// Literal search (--fixed-strings) #[test] fn test_fixed_strings() {