「cannot set LC_ALL」ロケール警告の解決
この記事で解決できること
cannot set LC_ALL/setlocale警告が なぜ出るのか が分かる- どの環境変数が原因かを
locale/locale -aで 即切り分け できる - 警告を 応急処置で止める方法 と、ロケールを生成して 恒久解決する手順 が身につく
結論(切り分けの型)
- 警告の正体は「要求したロケールがシステムに存在しない」の 1 点
- まず
localeで警告を、locale -aで 手元にあるロケール を確認する - 無ければ
locale-genで生成、急ぐならexport LC_ALL=Cで黙らせる
前提(対象環境)
- OS: Ubuntu / Debian / RHEL 系(glibc + systemd)
- ローカル端末・SSH 接続先サーバ・コンテナのいずれでも発生しうる
「cannot set LC_ALL」警告はなぜ出るのか?
結論:
LANG/LC_*環境変数が指すロケール(例en_US.UTF-8)が、そのシステムに生成・インストールされていないため。存在しないロケールを要求され、glibc が C ロケールへフォールバックする。
ロケールは「言語・文字コード・日付や数値の書式」をまとめた設定で、en_US.UTF-8 や ja_JP.UTF-8 のような名前を持つ。プログラムは起動時に setlocale() を呼び、LC_ALL → LC_* → LANG の優先順で要求するロケールを決める。
このとき要求した名前がシステムに存在しないと、glibc は警告を出して安全な C(POSIX)ロケールにフォールバックする。典型的なメッセージは次の通り。
# locale コマンド自身
locale: Cannot set LC_ALL to default locale: No such file or directory
# bash / 各種コマンド
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory
# perl(apt や 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").
「存在しない」の主なパターン
localesパッケージ自体が入っていない(最小構成のコンテナ・クラウドイメージ)- パッケージは入っているが、そのロケールが生成されていない(
locale-gen未実行) - SSH で手元の端末のロケールが転送され、接続先サーバに同じロケールが無い
- タイプミス(
en_US.utf8とen_US.UTF-8等)で存在しない名前を指している
どの環境変数がずれているかをどう確認するか
結論:
localeで現在値と警告対象の変数を、locale -aで利用可能なロケール一覧を確認する。要求している名前が一覧に無ければ、それが原因。
まず locale を実行すると、現在の設定と「どの変数が問題か」が同時に分かる。
$ 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=
次に、そのシステムで実際に使えるロケールを一覧する。
$ locale -a
C C.UTF-8 POSIX
この例では en_US.UTF-8 を要求しているのに、一覧には C 系しか無い。要求名が locale -a に出てこないことが、警告の決定的な証拠になる。
名前の表記ゆれに注意。locale -a は en_US.utf8(小文字・ハイフン無し)形式で表示することがあるが、LANG=en_US.UTF-8 形式の指定でも同一として扱われる。一方で en_US(文字コード無し)と en_US.UTF-8 は別物なので、サフィックスまで一致しているか確認する。
SSH 接続で警告が出るのはなぜか
結論: SSH クライアントが
SendEnv LANG LC_*で手元のロケールをサーバへ転送し、サーバ側がAcceptEnvで受け入れるため。サーバにそのロケールが無いと、ログインのたびに警告が出る。
「ローカルでは出ないのにサーバに SSH すると毎回出る」場合、原因はほぼこれ。多くのディストリの SSH クライアント設定には次の行がある。
# /etc/ssh/ssh_config もしくは ~/.ssh/config SendEnv LANG LC_*
これにより手元の LANG=ja_JP.UTF-8 などがサーバへ送られる。サーバ側 /etc/ssh/sshd_config の AcceptEnv LANG LC_* が受け取り、セッションの環境変数に設定する。サーバにそのロケールが無ければ、シェル起動時に setlocale が失敗する。
対処は 2 択。サーバ側にロケールを入れる(後述の生成手順)か、転送をやめる。転送を止めるならクライアント側の設定を書き換える。
# ~/.ssh/config で特定ホストだけ転送を無効化
Host myserver
SendEnv -LANG -LC_*特定の接続だけ一時的に転送を止めたいなら、ssh の -o で上書きできる。
$ ssh -o SendEnv= user@myserver
ロケールを生成・インストールするには?(Debian / Ubuntu)
結論:
localesパッケージを入れ、locale-genで目的のロケールを生成し、update-localeで既定値を設定する。対話式のdpkg-reconfigure localesでも同じことができる。
Debian / Ubuntu ではロケールは「パッケージ導入」と「生成」の 2 段階。
# 1. locales パッケージ(未導入の最小環境向け) $ sudo apt update && sudo apt install -y locales # 2. 目的のロケールを生成 $ sudo locale-gen en_US.UTF-8 ja_JP.UTF-8 # 3. システム既定のロケールを設定 $ sudo update-locale LANG=en_US.UTF-8
生成済みかは locale -a で再確認する。設定の永続先は /etc/default/locale。
$ cat /etc/default/locale
LANG=en_US.UTF-8
対話メニューで選びたい場合は次のコマンドを使う。表示された一覧からロケールをスペースキーで選択して生成する。
$ sudo dpkg-reconfigure locales
update-locale の変更や /etc/default/locale は 新しいログインセッションから反映される。現在のシェルにすぐ効かせたいなら、一度ログアウト・再ログインするか、export LANG=en_US.UTF-8 で当座の値を入れる。
RHEL / Fedora 系での直し方
結論: RHEL 8 以降は
glibc-langpack-<lang>パッケージでロケールを導入し、localectl set-localeで既定値を設定する。
RHEL / CentOS Stream / Fedora 系では、言語ごとの langpack を入れる方式。
# 英語ロケール一式 $ sudo dnf install -y glibc-langpack-en # 日本語が必要なら $ sudo dnf install -y glibc-langpack-ja # システム既定を設定 $ sudo localectl set-locale LANG=en_US.UTF-8
localectl は systemd 系で共通のロケール管理コマンドで、設定は /etc/locale.conf に書き込まれる。現在値は localectl status で確認できる。
$ localectl status
System Locale: LANG=en_US.UTF-8
VC Keymap: us
X11 Layout: us
Debian 系でも localectl(systemd)が使える環境なら localectl set-locale で既定値を設定できる。ただしロケールの生成自体は locale-gen が担うため、生成 → localectl の順は変わらない。
今すぐ黙らせたいときの応急処置
結論:
export LC_ALL=Cまたはexport LANG=C.UTF-8で、存在が保証されたロケールに切り替える。根本解決ではないが、警告を即座に止められる。
スクリプト実行やワンショットの作業で「今だけ警告を消したい」場合、確実に存在する C 系ロケールを指定する。
# 警告を完全に止める(英語メッセージ・ASCII 照合になる) $ export LC_ALL=C # UTF-8 を維持したい場合(多くの環境で利用可能) $ export LANG=C.UTF-8 $ unset LC_ALL
C(= POSIX)と C.UTF-8 は glibc に組み込まれており、locale-gen 不要でほぼ確実に使える。C.UTF-8 を選べば、英語メッセージながら UTF-8 のバイト列は壊れずに扱える。
LC_ALL はすべての LC_* を上書きする最優先変数。これを C に固定すると、日本語の文字種判定やソート順も C ロケールになる。恒久設定(.bashrc 等)に LC_ALL=C を書くと別の不具合を招くため、応急処置に留め、恒久対処はロケール生成で行う。
スクリプト単体で警告を抑えたいだけなら、先頭で次のように限定するのが安全。
#!/usr/bin/env bash export LC_ALL=C.UTF-8
再発させないためのチェックリスト
結論: サーバに必要なロケールを生成済みにし、不要な SSH 転送を止め、
LC_ALLの恒久固定を避ければ、ロケール警告はほぼ防げる。
| 対策 | コマンド / 設定 | 効果 |
|---|---|---|
| 必要なロケールを生成 | sudo locale-gen en_US.UTF-8 |
要求名の不在を解消 |
| システム既定を明示 | update-locale / localectl set-locale |
ログインごとの既定値を固定 |
| 不要な SSH 転送を止める | SendEnv -LANG -LC_* |
存在しないロケールの持ち込み防止 |
| 応急処置は局所に留める | スクリプト内 export LC_ALL=C.UTF-8 |
恒久固定による副作用を回避 |
コピペ用:ロケール診断ワンライナー
# 要求中のロケールと利用可能な一覧を並べて確認 echo "--- requested ---"; locale 2>&1 | grep -E '^(LANG|LC_ALL|LC_CTYPE)='; \ echo "--- available ---"; locale -a