diff --git a/src/uu/pr/src/pr.rs b/src/uu/pr/src/pr.rs index fd9c9cd1603..3d830d909a7 100644 --- a/src/uu/pr/src/pr.rs +++ b/src/uu/pr/src/pr.rs @@ -1501,7 +1501,14 @@ fn write_columns( }; let blank_line = FileLine::default(); + // Without a page trailer there is nothing to pad the page out to. + let no_trailer = feed_line_present || !options.display_header_and_trailer; for row in table { + // Merged files are padded with empty cells to fill the page; once + // every file has run out there is nothing left to print. + if merge && no_trailer && row.iter().all(Option::is_none) { + break; + } // On a page that is not completely filled the last row stops part way // through, and its final cell must not be followed by a column // separator. Merging prints an empty cell for every column instead, so @@ -1532,10 +1539,7 @@ fn write_columns( // The last row of a partly filled page has content in its leading // columns and nothing in the rest, so it still needs to be terminated. // Only a row without any content at all means the page ran out. - if cells_written == 0 - && not_found_break - && (feed_line_present || !options.display_header_and_trailer) - { + if cells_written == 0 && not_found_break && no_trailer { break; } writer.write_all(line_separator)?; diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index 9f4f050723d..af32d3d30be 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -701,6 +701,29 @@ fn test_join_lines_keeps_column_separator() { .stdout_is("1\t3\n2\t4\n"); } +#[test] +fn test_merge_stops_after_last_line_without_header() { + // without a page trailer there is nothing to pad to: like GNU pr, stop + // after the last merged line (-F still prints the 5 header lines and a form feed) + // -J keeps the columns from being padded, so the lines are short + let body = "a\tc\nb\td\n"; + let header = format!("\n\nX{}Page 1\n\n\n", " ".repeat(65)); + for (args, expected) in [ + (vec!["-J", "-t"], body.to_string()), + (vec!["-J", "-T"], body.to_string()), + (vec!["-J", "-F", "-D", "X"], format!("{header}{body}\x0c")), + ] { + let (at, mut ucmd) = at_and_ucmd!(); + at.write("one", "a\nb\n"); + at.write("two", "c\nd\n"); + ucmd.arg("-m") + .args(&args) + .args(&["one", "two"]) + .succeeds() + .stdout_is(expected); + } +} + #[test] fn test_value_for_number_lines() { // *5 is of the form [SEP[NUMBER]] so is accepted and succeeds