On Wed, Jun 24, 2026, 16:53 Chet Ramey <[email protected]> wrote:
>
> On 6/19/26 5:32 PM, Grisha Levit wrote:
> > On Fri, Jun 19, 2026 at 3:39 PM Chet Ramey via Bug reports for the GNU
> > Bourne Again SHell <[email protected]> wrote:
> >> I can't reproduce your results with bash-5.3, but I am not using Homebrew.
> >
> > I can reproduce this if, in System Settings : Language & Region, I have:
> > * "Region" set to "Germany"
> > * "English" as the first entry in "Preferred Languages"
> > Note that the language has to be "English" (or "English (UK)"), and not
> > "English (US)".
> >
> >      $ defaults read -g AppleLocale
> >      en_DE
>
> OK, I was able to reproduce this with the same settings.
>
> The default locale returned by setlocale(LC_ALL, "") is
>
> "de_DE/UTF-8/de_DE/de_DE/de_DE/C"
>
> which is supposedly an opaque string that can be fed back to setlocale().
>
> libintl setlocale also saves a copy of the default locale as returned by
>
> CFPreferencesCopyAppValue (CFSTR ("AppleLocale"),
>                             kCFPreferencesCurrentApplication);
>
> This returns "en_DE" (see below).
>
> >
> >      $ env -i ./bash -c \
> >          "printf '%f\n' 1; LC_NUMERIC=C printf '%f\n' 2; printf '%f\n' 3"
> >      1,000000
> >      2.000000
> >      ./bash: line 1: warning: setlocale: LC_NUMERIC: cannot change locale
> >      (): No such file or directory
>
> This happens because setlocale(LC_NUMERIC, "") ends up (down in libintl)
> attempting to set LC_NUMERIC to "en_DE" (the cached value saved above from
> the "AppleLocale" preference), which fails and returns NULL.
>
> Since it returns NULL, the current locale (C) remains unchanged. However,
> even if bash used the return value from setlocale() when it sets LC_NUMERIC
> from the temporary environment assignment, the results would not change,
> because that returns "C".
>
>
> > Setting LANG or LC_ALL instead of LC_NUMERIC in the temp env works as
> > expected though:
> >
> >      $ env -i ./bash -c \
> >          "printf '%f\n' 1; LC_ALL=C printf '%f\n' 2; printf '%f\n' 3"
> >      1,000000
> >      2.000000
> >      3,000000
>
> I suspect the reason is that bash sets all the locale variables itself
> when LC_ALL is changed. In this case, it tries to set everything to "",
> including LC_NUMERIC, and everything fails except LC_ALL, which succeeds
> and sets the locale back to en_DE.
>
> Bash does this because setlocale (...) works with environment variables,
> not shell variables, and bash can't guarantee that it can replace getenv().
>
> >
> > As does setting LC_NUMERIC as a non-temp env variable:
> >
> >      $ env -i ./bash -c \
> >          "printf '%f\n' 1; LC_NUMERIC=C; printf '%f\n' 2; printf '%f\n' 3"
> >      1,000000
> >      2.000000
> >      3.000000
>
> Well, of course. This should change the LC_NUMERIC category to "C" for the
> shell process until it gets changed again.
>
> > I think the only unexpected behavior here is that undoing an LC category
> > change done in the temp env doesn't work correctly.
>
> Because the return value from setlocale() (the current locale) isn't
> something that can be fed back to setlocale() without an error.

I think this behavior might just be a gnulib bug?

AFAICT, what happens in this case (no relevant variables in the
environment, System Preferences Language/Region set such that they do
not match a valid locale):

libintl_setlocale(LC_ALL,"") will set the LC_NUMERIC category (and others) by:
* checking the value of the "AppleLocale" preference value (en_DE)
* calling the system setlocale with this value (which fails)
* finding an appropriate locale name based on the territory (de_DE)
* calling the system setlocale with this value

libintil_setlocale(LC_NUMERIC, "") uses a different code path, which
does not do the last two steps, and so will just fail.

Reply via email to