Corrigindo Avisos "cannot set LC_ALL" de Locale

Corrigindo Avisos "cannot set LC_ALL" de Locale

O Que Voce Vai Aprender

  • Por que o aviso cannot set LC_ALL / setlocale aparece
  • Como identificar a variavel ofensora com locale / locale -a
  • Como silenciar rapidamente e como gerar o locale para uma correcao permanente

Conclusao (padrao de triagem)

  • O aviso significa uma coisa: o locale solicitado nao existe no sistema
  • Primeiro verifique o aviso com locale, depois os locales que voce realmente tem com locale -a
  • Se estiver ausente, gere com locale-gen; se tiver pressa, silencie com export LC_ALL=C

Premissas (ambiente alvo)

  • SO: Ubuntu / Debian / familia RHEL (glibc com systemd)
  • Pode acontecer em terminal local, servidor SSH alvo ou container

Por que o aviso "cannot set LC_ALL" aparece?

Conclusao: Porque o locale que suas variaveis LANG / LC_* solicitam (ex: en_US.UTF-8) nao esta gerado ou instalado naquele sistema. Ao solicitar um locale que nao existe, a glibc faz fallback para o locale C.

Um locale agrupa idioma, codificacao de caracteres e formatacao de data/numero sob um nome como en_US.UTF-8 ou ja_JP.UTF-8. Na inicializacao, um programa chama setlocale() e resolve o locale solicitado na ordem de prioridade: LC_ALLLC_*LANG.

Quando o nome solicitado nao existe no sistema, a glibc emite um aviso e faz fallback para o locale seguro C (POSIX). Mensagens tipicas:

# o proprio comando locale
locale: Cannot set LC_ALL to default locale: No such file or directory

# bash / varios comandos
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory

# perl (comum em apt e hooks do Git)
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
	LC_ALL = (unset),
	LC_CTYPE = "UTF-8",
	LANG = "en_US.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

Principais padroes de "nao existe"

  • O pacote locales em si nao esta instalado (containers minimos, imagens cloud)
  • O pacote esta presente mas o locale nunca foi gerado (locale-gen nao executado)
  • O SSH encaminhou o locale do seu terminal e o servidor alvo nao tem o mesmo
  • Um erro de digitacao (ex: omitir o codeset como em en_US em vez de en_US.UTF-8, ou separador errado como en-US.UTF-8) aponta para um nome que nao existe

Como encontro qual variavel esta errada?

Conclusao: Use locale para os valores atuais e a variavel ofensora, e locale -a para a lista de locales disponiveis. Se o nome solicitado nao esta na lista, essa e a causa.

Executar locale mostra as configuracoes atuais e qual variavel e o problema de uma vez.

$ locale
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
...
LC_ALL=

Em seguida, liste os locales que o sistema pode realmente usar.

$ locale -a
C
C.UTF-8
POSIX

Aqui en_US.UTF-8 e solicitado, mas a lista tem apenas locales da familia C. O nome solicitado nao aparecer em locale -a e a evidencia decisiva.

Atencao para variacoes de nome. locale -a pode imprimir na forma en_US.utf8 (minusculo, sem hifen), mas uma configuracao LANG=en_US.UTF-8 e tratada como a mesma. Entretanto, en_US (sem codificacao) e en_US.UTF-8 sao diferentes, entao verifique se o sufixo tambem corresponde.

Por que o aviso aparece via SSH?

Conclusao: O cliente SSH encaminha seu locale local com SendEnv LANG LC_*, e o servidor aceita via AcceptEnv. Se o servidor nao tem aquele locale, voce recebe o aviso em cada login.

Se nunca aparece localmente mas aparece toda vez que voce se conecta via SSH a um servidor, esta e quase sempre a causa. A maioria das distros vem com uma configuracao de cliente SSH com esta linha:

# /etc/ssh/ssh_config ou ~/.ssh/config
SendEnv LANG LC_*

Isso envia seu LANG=en_US.UTF-8 (e similares) para o servidor. O AcceptEnv LANG LC_* do /etc/ssh/sshd_config do servidor os recebe e configura o ambiente da sessao. Se o servidor nao tem aquele locale, setlocale falha quando o shell inicia.

Voce tem duas opcoes: instalar o locale no servidor (passos abaixo) ou parar de encaminha-lo. Para parar o encaminhamento, edite a configuracao do cliente.

# Desabilitar encaminhamento para um host em ~/.ssh/config
Host myserver
    SendEnv -LANG -LC_*

Para evitar o aviso de locale em uma unica conexao, envie o locale C que esta sempre presente para sobrescreve-lo. LC_ALL tem precedencia sobre todos os outros LC_* e LANG, entao ele vence mesmo quando um valor foi encaminhado.

$ LC_ALL=C ssh user@myserver

Como gerar ou instalar o locale? (Debian / Ubuntu)

Conclusao: Instale o pacote locales, gere o locale alvo com locale-gen e defina o padrao com update-locale. O interativo dpkg-reconfigure locales faz o mesmo.

No Debian / Ubuntu, um locale requer dois passos: instalar o pacote e gera-lo.

# 1. O pacote locales (para sistemas minimos sem ele)
$ sudo apt update && sudo apt install -y locales

# 2. Gerar os locales alvo
$ sudo locale-gen en_US.UTF-8 ja_JP.UTF-8

# 3. Definir o locale padrao do sistema
$ sudo update-locale LANG=en_US.UTF-8

Verifique novamente com locale -a que foi gerado. A configuracao persistente fica em /etc/default/locale.

$ cat /etc/default/locale
LANG=en_US.UTF-8

Para escolher de um menu, use o comando abaixo e selecione locales com a barra de espaco para gera-los.

$ sudo dpkg-reconfigure locales

Mudancas de update-locale e /etc/default/locale so entram em vigor a partir de uma nova sessao de login. Para aplica-las ao shell atual imediatamente, faca logout e login novamente, ou defina um valor por enquanto com export LANG=en_US.UTF-8.

Corrigindo no RHEL / Fedora

Conclusao: No RHEL 8 e posterior, instale o locale via pacote glibc-langpack-<lang> e defina o padrao com localectl set-locale.

No RHEL / CentOS Stream / Fedora, voce instala um langpack por idioma.

# O conjunto de locale ingles
$ sudo dnf install -y glibc-langpack-en

# Adicione japones se precisar
$ sudo dnf install -y glibc-langpack-ja

# Definir o padrao do sistema
$ sudo localectl set-locale LANG=en_US.UTF-8

localectl e o comando comum de gerenciamento de locale em sistemas systemd, e ele escreve a configuracao em /etc/locale.conf. Verifique o valor atual com localectl status.

$ localectl status
   System Locale: LANG=en_US.UTF-8
       VC Keymap: us
      X11 Layout: us

Em um sistema da familia Debian que tambem tem localectl (systemd), voce pode definir o padrao com localectl set-locale tambem. Mas gerar o locale continua sendo trabalho do locale-gen, entao a ordem gerar → localectl permanece a mesma.

Um workaround rapido quando voce so quer silenciar

Conclusao: Use export LC_ALL=C ou export LANG=C.UTF-8 para mudar para um locale que certamente existe. Nao e uma correcao real, mas para o aviso instantaneamente.

Para uma execucao de script ou tarefa pontual onde voce "so quer que o aviso pare agora", aponte para um locale da familia C que certamente existe.

# Silenciar completamente (mensagens em ingles, collation ASCII)
$ export LC_ALL=C

# Manter UTF-8 (disponivel na maioria dos sistemas)
$ export LANG=C.UTF-8
$ unset LC_ALL

C (= POSIX) e C.UTF-8 sao embutidos na glibc e funcionam em quase todo lugar sem locale-gen. Escolher C.UTF-8 mantem sequencias de bytes UTF-8 intactas enquanto usa mensagens em ingles.

LC_ALL e a variavel de maior prioridade que sobrescreve todo LC_*. Fixa-la em C forca a classificacao de caracteres e ordem de ordenacao para o locale C tambem. Colocar LC_ALL=C em um arquivo permanente (como .bashrc) convida outros bugs, entao mantenha como workaround e corrija permanentemente gerando o locale.

Se voce so quer silenciar um unico script, delimite no topo.

#!/usr/bin/env bash
export LC_ALL=C.UTF-8

Checklist para prevenir recorrencia

Conclusao: Pre-gere os locales que um servidor precisa, pare forwarding SSH desnecessario e evite fixar LC_ALL permanentemente, e avisos de locale sao amplamente preveniveis.

Medida Comando / configuracao Efeito
Gerar locales necessarios sudo locale-gen en_US.UTF-8 Remove o nome solicitado ausente
Definir padrao explicito do sistema update-locale / localectl set-locale Fixa o padrao por login
Parar forwarding SSH desnecessario SendEnv -LANG -LC_* Previne importacao de locales ausentes
Manter workarounds locais export LC_ALL=C.UTF-8 dentro de script Evita efeitos colaterais de fixacao global

Copie e cole: diagnostico de locale em uma linha

# Compare o locale solicitado contra o que esta disponivel
echo "--- solicitado ---"; locale 2>&1 | grep -E '^(LANG|LC_ALL|LC_CTYPE)='; \
  echo "--- disponivel ---"; locale -a

Proximas Leituras