diff --git a/src/uu/wc/src/wc.rs b/src/uu/wc/src/wc.rs index 90c80752f74..5aef27eb72b 100644 --- a/src/uu/wc/src/wc.rs +++ b/src/uu/wc/src/wc.rs @@ -45,6 +45,30 @@ use crate::{ /// The minimum character width for formatting counts when reading from stdin. const MINIMUM_WIDTH: usize = 7; +/// Returns the byte size of stdin if it is a regular file (e.g. `wc -c < file`). +/// Returns `None` for pipes, terminals, sockets, etc. so we fall back to normal counting. +fn try_get_stdin_size() -> Option { + #[cfg(unix)] + { + use rustix::fd::AsFd; + + let stdin = io::stdin(); + let fd = stdin.as_fd(); + + let Ok(stat) = rustix::fs::fstat(fd) else { + return None; + }; + + if rustix::fs::FileType::from_raw_mode(stat.st_mode) == rustix::fs::FileType::RegularFile { + return Some(stat.st_size as usize); + } + None + } + #[cfg(not(unix))] + { + None // TODO: Implement Windows support + } +} struct Settings<'a> { show_bytes: bool, show_chars: bool, @@ -482,6 +506,16 @@ fn word_count_from_reader( // show_bytes (true, false, false, false, false) => { + // Fast path: if stdin is a regular file, get size from metadata (no reading needed) + if let Some(bytes) = try_get_stdin_size() { + return ( + WordCount { + bytes, + ..WordCount::default() + }, + None, + ); + } // Fast path when only show_bytes is true. let (bytes, error) = count_bytes_fast(&mut reader); (