diff --git a/src/uucore/src/lib/features/i18n/mod.rs b/src/uucore/src/lib/features/i18n/mod.rs index b834c17d4f..c8db6dbb5e 100644 --- a/src/uucore/src/lib/features/i18n/mod.rs +++ b/src/uucore/src/lib/features/i18n/mod.rs @@ -38,7 +38,7 @@ const DEFAULT_LOCALE: Locale = locale!("und"); pub fn get_locale_from_env(locale_name: &str) -> (Locale, UEncoding) { let locale_var = ["LC_ALL", locale_name, "LANG"] .iter() - .find_map(|&key| std::env::var(key).ok()); + .find_map(|&key| std::env::var(key).ok().filter(|v| !v.is_empty())); if let Some(locale_var_str) = locale_var { let mut split = locale_var_str.split(&['.', '@']); diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 186f942e1a..f91f6a416f 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -3384,6 +3384,27 @@ mod quoting { .succeeds() .stdout_is("é\n"); } + + #[test] + fn test_empty_lc_all_falls_through_to_lang() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + // Create a file with a non-ASCII character. + at.touch("café"); + + // When LC_ALL is empty it should be treated as unset, + // falling through to LANG for locale resolution. + // Without the fix, empty LC_ALL was treated as POSIX, + // causing the non-ASCII name to be octal-escaped. + scene + .ucmd() + .env("LC_ALL", "") + .env("LANG", "en_US.UTF-8") + .env("LC_CTYPE", "en_US.UTF-8") + .args(&["--quoting-style=literal"]) + .succeeds() + .stdout_contains("café"); + } } #[test]