diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 0351227eb..6317c1975 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1139,7 +1139,13 @@ fn sort_entries(entries: &mut Vec, config: &Config) { entries.sort_by_key(|k| Reverse(k.md().as_ref().map(|md| md.len()).unwrap_or(0))) } // The default sort in GNU ls is case insensitive - Sort::Name => entries.sort_by_cached_key(|k| k.file_name.to_lowercase()), + Sort::Name => entries.sort_by_cached_key(|k| { + let has_dot: bool = k.file_name.starts_with('.'); + let filename_nodot: &str = &k.file_name[if has_dot { 1 } else { 0 }..]; + // We want hidden files to appear before regular files of the same + // name, so we need to negate the "has_dot" variable. + (filename_nodot.to_lowercase(), !has_dot) + }), Sort::Version => entries.sort_by(|k, j| version_cmp::version_cmp(&k.p_buf, &j.p_buf)), Sort::None => {} } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 09e02f264..da45934e9 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -481,6 +481,21 @@ fn test_ls_sort_name() { .arg("--sort=name") .succeeds() .stdout_is(["test-1", "test-2", "test-3\n"].join(sep)); + + // Order of a named sort ignores leading dots. + let scene_dot = TestScenario::new(util_name!()); + let at = &scene_dot.fixtures; + at.touch(".a"); + at.touch("a"); + at.touch(".b"); + at.touch("b"); + + scene_dot + .ucmd() + .arg("--sort=name") + .arg("-A") + .succeeds() + .stdout_is([".a", "a", ".b", "b\n"].join(sep)); } #[test]