diff --git a/src/uu/head/src/take.rs b/src/uu/head/src/take.rs index 6f05b77e595..b557036579f 100644 --- a/src/uu/head/src/take.rs +++ b/src/uu/head/src/take.rs @@ -163,6 +163,7 @@ impl TakeAllLinesBuffer { reader: &mut impl Read, separator: u8, ) -> std::io::Result { + self.partial_line = false; let bytes_read = self.inner.fill_buffer(reader)?; // Count the number of lines... self.terminated_lines = memchr_iter(separator, self.inner.remaining_buffer()).count(); diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index 2acc783eaff..e35d347f3b3 100644 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -451,6 +451,35 @@ fn test_all_but_last_bytes_large_file_piped() { .stdout_only_fixture(seq_19000_file_name); } +#[test] +fn test_all_but_last_lines_large_file_presume_input_pipe() { + // Validate print-all-but-last-n-lines on the non-seekable path for a large terminated input. + // This input shape forces repeated buffer reuse while some chunks end mid-line. + let scene = TestScenario::new(util_name!()); + let fixtures = &scene.fixtures; + + let input_file_name = "reused_line_chunks"; + let expected_output_file_name = "reused_line_chunks_elide_last"; + let line = "aaaaaa\n"; + let input_line_count: usize = 20_000; + + let mut input = String::with_capacity(line.len() * input_line_count); + for _ in 0..input_line_count { + input.push_str(line); + } + fixtures.write(input_file_name, &input); + fixtures.write( + expected_output_file_name, + &line.repeat(input_line_count - 1), + ); + + scene + .ucmd() + .args(&["---presume-input-pipe", "-n", "-1", input_file_name]) + .succeeds() + .stdout_only_fixture(expected_output_file_name); +} + #[test] fn test_all_but_last_lines_large_file() { // Create our fixtures on the fly. We need the input file to be at least double