From 53340039bc3535ad3e72d514b835b1893d77a5af Mon Sep 17 00:00:00 2001 From: Charlie Tonneslan Date: Sat, 16 May 2026 18:14:53 -0400 Subject: [PATCH] sort: don't accept leading '+' in numeric (-n) sort Rust's f64 parser happily accepts "+1" as 1.0, so the whole-line numeric fast path was treating "+1", "+10", "+2" as numbers and sorting them numerically. GNU sort -n explicitly rejects a leading '+' (that's reserved for -g), so the lines should compare lexicographically and end up in their original order. Reject inputs containing '+' from the fast path so they fall through to the regular comparator, which already does the right thing. Closes #10315. Signed-off-by: Charlie Tonneslan --- src/uu/sort/src/sort.rs | 5 +++-- tests/by-util/test_sort.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 9d117d1523a..a6926028873 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -668,8 +668,9 @@ impl<'a> Line<'a> { ); } if settings.mode == SortMode::Numeric { - // exclude inf, nan, scientific notation - let line_num_float = (!line.iter().any(u8::is_ascii_alphabetic)) + // exclude inf, nan, scientific notation, and a leading '+' which + // GNU sort -n doesn't accept (only -g does). + let line_num_float = (!line.iter().any(|&b| b.is_ascii_alphabetic() || b == b'+')) .then(|| std::str::from_utf8(line).ok()) .flatten() .and_then(|s| s.parse::().ok()); diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 05337174260..3fa72401101 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -418,6 +418,18 @@ fn test_numeric_unsorted_ints() { ); } +#[test] +fn test_numeric_leading_plus_not_numeric() { + // GNU sort -n doesn't accept a leading '+' as a sign, so "+1", "+10", "+2" + // should compare lexicographically (i.e., stay in their original order + // since sort is stable on equal keys), not numerically. + new_ucmd!() + .arg("-n") + .pipe_in("+1\n+10\n+2\n") + .succeeds() + .stdout_is("+1\n+10\n+2\n"); +} + #[test] fn test_human_block_sizes() { test_helper(