Skip to content

sort: read lowercase SI units with -h and -f - #15644

Merged
sylvestre merged 2 commits into
uutils:mainfrom
ozenyunus35:sort-human-fold-case
Oct 24, 2026
Merged

sylvestre merged 2 commits into
uutils:mainfrom
ozenyunus35:sort-human-fold-case

Conversation

@ozenyunus35

Copy link
Copy Markdown
Contributor

Fixes #15577

With -h, -f had no effect. GNU sort folds case before the human-numeric compare, so 2m is read as 2M and 1e as 1E. uutils read a lowercase unit other than k as no unit, both for the global -h -f and for a key like -k2,2hf.

  • NumInfoParseSettings gets a fold_si_units flag. When it is set, NumInfo::parse also includes a lowercase unit in the number's range. FieldSelector::get_selection sets it from the key's ignore_case.
  • get_unit reads the lowercase units like the uppercase ones. A lowercase unit other than k is only in the range when the key folds case, so nothing changes without -f. I wrote it as a match instead of the position search. With only an uppercase conversion added, sort -h on 5M lines was about 3% slower. With the match it takes the same time as main.
  • --debug keeps marking a lowercase unit as outside the key, even with -f. GNU 9.12 does the same (2m is underlined as _, not __).
export LC_ALL=C
printf '2m\n1K\n' | sort -h -f
# before: 2m / 1K
# after:  1K / 2m          (same as GNU 9.12)

printf 'a 1e\nb 1K\n' | sort -k2,2hf
# before: a 1e / b 1K
# after:  b 1K / a 1e      (same as GNU 9.12)

I added test_human_numeric_ignore_case. It checks -h -f, -hf and -k1,1hf, and that -h and -f -k1h (where the key has its own options and does not inherit -f) still don't read lowercase units. It fails without the change, and all test_sort tests and the uu_sort unit tests pass.

I also compared 18 option combinations with GNU 9.12 on input with lowercase and uppercase units, negative values, 0m, -0m and a bare m: -h, -h -f, -hf, -fh, with -r, -u, -s, -c, --debug, and keys like -k1,1hf, -f -k1,1h and -k2,2hf. The output was the same for all of them.

The sort_bench benchmarks have no -h case, and their results only moved by run-to-run noise. I also timed a release build of sort -h --parallel=1 on 5M lines against main: 3.32–3.40 s on main and 3.33–3.37 s with the change.

I used an AI assistant to help draft parts of the code and tests; I reviewed the changes and ran the tests myself.

With -f, GNU sort -h reads 2m as 2M and 1e as 1E. uutils ignored -f
on this path and treated a lowercase unit other than k as no unit.
The key parser now accepts lowercase units when the key folds case,
and get_unit maps them to the uppercase ones. --debug still marks
them as outside the key, as GNU does. Fixes uutils#15577.
@codspeed

codspeed Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning, 1 note

⚠️ 123 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

ℹ️ 1 benchmark has no flamegraph

The flamegraph wasn't generated: most of the time was spent in runtime internals, which would leave nothing useful to analyze.

See affected benchmarks

✅ 401 untouched benchmarks
⏩ 70 skipped benchmarks1


Comparing ozenyunus35:sort-human-fold-case (bea2a2f) with main (18bc31f)

Open in CodSpeed

Footnotes

  1. 70 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

Comment thread src/uu/sort/src/sort.rs
let mut parse_settings = settings
.numeric_locale
.num_info_settings(selector.settings.mode == SortMode::HumanNumeric);
.num_info_settings(selector.settings.mode == SortMode::HumanNumeric, false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add a --debug -h -f case to the test so this stays aligned with GNU?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sylvestre Added test_human_numeric_ignore_case_debug, which checks the --debug -h -f output against GNU's.

@github-actions

Copy link
Copy Markdown

Binary size comparison:

Individual binary size comparison VS main (threshold: >=5% AND >=4 KB).

Total size of compared binaries: 155.04 MB (-304 KB, -0.19%)

Significant per-binary changes:
  date     2.61 MB ->    2.30 MB  (-316 KB, -11.81%)

@sylvestre
sylvestre merged commit 4695f0c into uutils:main Oct 24, 2026
232 of 233 checks passed
@sylvestre

Copy link
Copy Markdown
Contributor

Thanks for your PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sort: -h ignores -f, so lowercase suffixes such as m, g, e are not folded

2 participants