diff --git a/src/uu/wc/src/wc.rs b/src/uu/wc/src/wc.rs index 8b6b8dc4175..dcc4e96698c 100644 --- a/src/uu/wc/src/wc.rs +++ b/src/uu/wc/src/wc.rs @@ -46,6 +46,28 @@ 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; + }; + let file_type = rustix::fs::FileType::from_raw_mode(stat.st_mode); + if file_type == rustix::fs::FileType::RegularFile { + return Some(stat.st_size as usize); + } + None + } + #[cfg(not(unix))] + { + None + } +} struct Settings<'a> { show_bytes: bool, show_chars: bool, @@ -483,6 +505,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); (