sharkdp/fd
Exit codes
Defined by ExitCode in src/exit_codes.rs:
pub enum ExitCode {
Success,
HasResults(bool),
GeneralError,
KilledBySigint,
}Mapping to process exit status
| Variant | Process exit status | When fd returns this |
|---|---|---|
Success |
0 |
A normal search finished, regardless of whether anything matched (without -q/--quiet). All exec children also returned 0. |
HasResults(true) |
0 |
--quiet mode and at least one match. |
HasResults(false) |
1 |
--quiet mode and zero matches. |
GeneralError |
1 |
Anything went wrong: malformed pattern, invalid path, unreadable directory error in some cases, exec child returned non-zero, etc. The [fd error]: prefix on stderr typically explains why. |
KilledBySigint |
130 |
Ctrl-C was pressed. On Unix, fd re-installs the default SIGINT handler and re-raises the signal so callers see the conventional 128 + 2 = 130 status. |
Exit-code merging
When fd runs multiple commands (-x / -X), each one produces an exit code. They are merged via merge_exitcodes:
pub fn merge_exitcodes(results: impl IntoIterator<Item = ExitCode>) -> ExitCode {
if results.into_iter().any(ExitCode::is_error) {
return ExitCode::GeneralError;
}
ExitCode::Success
}Any non-zero result anywhere collapses the whole run to GeneralError. This applies to:
- The receiver's own outcome.
- Each
-xworker thread. - Each
-XCommandBuilder's success/failure.
Signal handling
ExitCode::exit does the right thing per variant:
pub fn exit(self) -> ! {
#[cfg(unix)]
if self == ExitCode::KilledBySigint {
unsafe {
if signal(Signal::SIGINT, SigHandler::SigDfl).is_ok() {
let _ = raise(Signal::SIGINT);
}
}
}
process::exit(self.into())
}The unsafe block re-raises SIGINT so calling shells see "fd was killed by SIGINT" rather than "fd exited 130 voluntarily" — a subtle but important distinction for shell scripts that check $?.
The Ctrl-C handler that produces KilledBySigint is installed in WorkerState::scan (src/walk.rs):
ctrlc::set_handler(move || {
quit_flag.store(true, Ordering::Relaxed);
if interrupt_flag.fetch_or(true, Ordering::Relaxed) {
ExitCode::KilledBySigint.exit();
}
}).unwrap();The first SIGINT lets the walker drain gracefully. A second one short-circuits to immediate exit.
Notable consequences
fd 'pattern_with_no_matches'exits 0. Use-qif you want a non-zero exit status to signal "no match".fd 'pat' -X falseexits 1 (becausefalsereturned non-zero), even though fd's traversal succeeded.- Pressing Ctrl-C during a long search produces exit status 130 on Unix and 1 on Windows (Rust does not have a clean equivalent of
raise(SIGINT)there). - A broken pipe in stdout (e.g.,
fd | head) is treated asGeneralErrorfrom the receiver's perspective; in practice this just meansfd | headexits cleanly because the kernel SIGPIPEs fd before the receiver decides anything.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.