diff --git a/src/uu/join/src/join.rs b/src/uu/join/src/join.rs index 49698eb511f..1a59f03ac73 100644 --- a/src/uu/join/src/join.rs +++ b/src/uu/join/src/join.rs @@ -279,9 +279,9 @@ impl Ord for CaseInsensitiveSlice<'_> { if let Some((s, o)) = std::iter::zip(self.v.iter(), other.v.iter()).find(|(s, o)| !s.eq_ignore_ascii_case(o)) { - // first characters that differ, return the case-insensitive comparison - let s = s.to_ascii_lowercase(); - let o = o.to_ascii_lowercase(); + // first characters that differ, compared folded to upper case like `sort -f` + let s = s.to_ascii_uppercase(); + let o = o.to_ascii_uppercase(); s.cmp(&o) } else { // one of the strings is a substring or equal of the other diff --git a/tests/by-util/test_join.rs b/tests/by-util/test_join.rs index c551196f738..3aae657dbfc 100644 --- a/tests/by-util/test_join.rs +++ b/tests/by-util/test_join.rs @@ -221,6 +221,26 @@ fn case_insensitive_prints_each_lines_own_key() { .stdout_only("B\nb\n"); } +#[test] +fn case_insensitive_matches_sort_f_order() { + // `sort -f` folds to upper case, so `_` sorts after letters. + let scene = TestScenario::new(util_name!()); + scene + .fixtures + .write("requested", "svcabc mallory\nsvc_backup mallory\n"); + scene.fixtures.write("reserved", "SVC_BACKUP\n"); + scene + .ucmd() + .args(&["-i", "-v", "1", "requested", "reserved"]) + .succeeds() + .stdout_only("svcabc mallory\n"); + scene + .ucmd() + .args(&["-i", "requested", "reserved"]) + .succeeds() + .stdout_only("svc_backup mallory\n"); +} + #[test] fn semicolon_separated() { new_ucmd!()