Linuxでファイル内の大文字を小文字に変換する方法

Linuxでファイル内容の大文字を小文字へ変える方法は、対象がASCII英字だけか、ロケールに従う非ASCII文字も含むかで分けます。ASCIIだけならLC_ALL=C tr '[:upper:]' '[:lower:]' < input.txt > output.newが予測しやすい基本形です。Unicodeを含む文章はGNU trの多バイト制約を踏まえ、UTF-8ロケール対応のgawkなどを候補にして実データで試します。どちらでも元ファイルと同じパスへ直接出力せず、大小を区別するID・URL・パス・トークンまで一括変換しないことが重要です。

目次

変換対象と文字集合を先に決める

要件を「ASCIIのA〜Zだけ」「現在ロケールで大文字と分類される文字」「Unicodeの完全な大文字小文字同一視」のどれかへ具体化します。これらは同じではありません。英数字ログの正規化と、各国語の人名処理では必要な道具・試験・期待結果が変わります。

全文、特定列、拡張子、ファイル名のどこを変えるかも区別します。ファイル内容の変換コマンドはファイル名を変えません。逆にファイル名の小文字化は名前衝突、リンク切れ、大小を区別しないファイルシステムの挙動が絡む別作業です。本記事の基本は内容を別ファイルへ出す手順です。

ASCIIだけならCロケールのtrを使う

LC_ALL=C tr '[:upper:]' '[:lower:]' < input.txt > output.newは、標準入力を読み標準出力へ書きます。Cロケールで文字クラスの対応を明示するため、ASCII英大文字を予測可能に小文字化し、その他のバイトはそのまま通します。まず短いコピーで期待結果を確認します。

cat input.txt | tr ...でも流せますが、単一ファイルなら入力リダイレクトの方が構造を読みやすく、余分なプロセスも不要です。trの文字列オペランドは正規表現ではなく文字配列です。角括弧クラスはシェル展開を防ぐため引用し、[:upper:]と[:lower:]を対にします。

A-Z範囲より文字クラスを優先する

tr 'A-Z' 'a-z'はよく見ますが、範囲の解釈はロケールや実装の注意点を伴います。ASCII限定ならCロケールと[:upper:]/[:lower:]の組み合わせで意図を示す方が明確です。ロケールを指定しないまま別ホストへコピーして同じ結果になると仮定しません。

trは入力ファイル名を直接受け取る通常のフィルターではなく、標準入力から読みます。複数ファイルを連結して渡すと境界が失われ、どの出力がどの入力由来か分かりにくくなります。ファイル単位の別出力を作り、入力名・出力名・終了状態を対応付けて記録します。

GNU trの多バイト文字制約を理解する

GNU Coreutilsの公式説明は、GNU trが安全に完全対応するのは一バイト文字ロケールであり、UTF-8のような多バイト文字に対する一般的な文字単位変換を完全には扱わないと説明しています。非ASCII文字をtrの集合へ直接並べると、文字ではなく構成バイトを変えてデータを壊す可能性があります。

したがってtr 'ÄÖÜ' 'äöü'のような方法をUTF-8本文へ使いません。ASCII英字だけを変えるCロケールの例と、非ASCIIの大小変換を明確に分けます。日本語本文中のASCII見出しだけを小文字化する用途でも、入力が正しいUTF-8か、変換対象外バイトが保持されたかをハッシュ以外の標本でも確認します。

非ASCII文字はUTF-8ロケール対応ツールで試す

GNU gawkはロケールの多バイト文字を文字として扱い、tolower(string)を提供します。利用可能なUTF-8ロケールをlocale -aで確認したうえで、例としてLC_ALL=ja_JP.UTF-8 gawk '{print tolower($0)}' -- input.txt > output.newを小さな標本へ試せます。ロケール名はOSにより異なるため存在確認なしに固定しません。

ロケール対応の小文字化はUnicodeの完全なケースフォールディングと同義ではなく、言語・文字・ライブラリ版によって期待結果を個別確認する必要があります。トルコ語のI、アクセント付き文字、ギリシャ語、ドイツ語など対象データに現れる境界例を用意し、検索用正規化ならアプリケーション側のUnicodeライブラリ要件も検討します。

gawkのprintが行終端へ与える影響を確認する

gawk '{print tolower($0)}'は各レコードをprintし、出力レコード区切りを付けます。そのため、最終改行がなかった入力へ改行が付く、CRLFがLFへ変わるなど、大小変換以外のバイト差が生じ得ます。本文内容だけでなく改行形式と最終改行の要件も決めます。

BOM、無効なUTF-8、混在符号化、NULを含むデータも通常テキストとは別扱いです。fileや生成元仕様で確認し、未知の符号化を推測で変換しません。符号化変換が必要なら、小文字化と別工程にして入力・出力の文字コード、エラー方針、代替文字の有無を検証します。

GNU sedの小文字化拡張は移植性を明記する

GNU sedの置換部にはLとlがあり、例としてsed 's/[[:upper:]]/\L&/g' -- input.txt > output.newと書けます。しかしこれはGNU拡張で、すべてのsedに移植できる標準機能ではありません。単純な全文ASCII変換なら、意図が明瞭なtrを基本にします。

sedを使う利点は、行の一部分やパターンに一致した箇所だけを変える場合です。それでも正規表現の文字クラスとロケール、GNU拡張、改行処理を確認します。macOSやBusyBoxなど別実装へ配るスクリプトでは、実装名と版を検出するか、POSIX範囲の別設計へ変えます。

特定列だけなら区切りと出力形式を保持する

表データの一列だけを小文字化するなら、全文へtrを掛けず、形式対応ツールで対象フィールドだけを変えます。単純なタブ区切りならgawk -F '\t' -v OFS='\t' '{$2=tolower($2); print}' -- data.tsv > output.newのようにできます。空欄、列不足、ヘッダーを先に確認します。

このawk例はフィールドを再構成するため、元の区切り数や見た目の空白が変わる場合があります。CSVへ-F,を使わず、引用符・埋め込み改行・出力時の再引用に対応したCSVパーサーを使います。ID列や署名列など大小を区別する列を対象に含めないよう、列名で許可リストを作ります。

入力と同じパスへのリダイレクトを禁止する

tr ... < input.txt > input.txtは安全な上書きではありません。Bashはコマンドを実行する前に>の出力ファイルを開いて切り詰めるため、trが読む時点で入力は空になります。awkやsedでも同じです。必ず別名の新規出力を作り、元ファイルを保持します。

ツールの-i相当を使う場合も、実装差、シンボリックリンク、ハードリンク、バックアップ拡張子、途中失敗、空き容量を調べます。最も監査しやすい手順は別ファイルへ生成し、検証後に承認された置換工程を実施することです。単発作業では置換せず派生ファイルとして渡す選択も有効です。

大小を区別する値を無差別に変換しない

パス、Linuxユーザー名、URLのパス部、APIトークン、パスワード、暗号鍵、ハッシュ、Base64、製品コード、データベース識別子は大小が意味を持つ場合があります。ログ全体を正規化すると、後で元の対象へ到達できない、認証情報が別値になる、監査証拠を改変する、といった問題が起きます。

変換対象を自然言語列や検索用コピーなどへ限定し、原本を不変で保管します。法務・監査ログでは派生物であること、使用した規則、日時、ツール版、原本ハッシュを記録します。秘密を含む入力を試験サイトや外部サービスへ送らず、ローカルの管理された環境で処理します。

小文字化は可逆変換ではない

Aとaがどちらもaになるため、出力だけから元の大小を復元できません。非ASCIIの大小対応では複数文字や文脈が絡む場合もあり、「逆に大文字化すれば戻る」という前提は成り立ちません。ロールバックには元ファイルまたは検証済みバックアップが必要です。

一意キーを小文字化すると、ABCとabcが衝突します。変換前に正規化後の重複を数え、衝突時は停止して解決規則を決めます。ファイル名、ユーザー名、メールローカル部、コード値など、仕様上の大小同一性が不明な項目を推測で統合しません。

複数ファイルはNUL区切りと別出力先で扱う

空白や改行を含むファイル名があるため、for f in $(find ...)のような空白分割を使いません。Bashならfindの-print0とNUL対応の読取を組み合わせ、入力ごとに一意な出力パスを作ります。変換済み出力ディレクトリを再検索して自己入力しないよう探索範囲を分離します。

並列化する場合はCPUだけでなくディスク帯域、同名出力、ログ混在、失敗時の再実行を考慮します。入力ごとの終了状態と件数を持ち、途中まで成功したバッチを全成功として扱いません。出力先ディレクトリの権限と空き容量を先に確認し、一時ファイルが他者へ読めないモードにします。

差分・件数・メタデータを検証してから渡す

出力後はcmpやdiff -uを小さな非機密標本へ使い、変更が期待した文字だけか確認します。行数、バイト数、改行形式、文字コード、無効文字、正規化後の重複も検査します。変更対象がなければ同一、対象があれば差分ありという期待をテストケースごとに決めます。

リダイレクトで作る新規ファイルは、元の所有者、モード、ACL、拡張属性、mtimeを自動では保持しません。置換するなら必要なメタデータ、同時利用プロセス、バックアップ、ロールバックを確認します。最後に元と出力のハッシュ、コマンド、ロケール、ツール版、承認者を記録し、原本を消さずに受け渡します。

確認チェックリスト

  • ASCII限定・ロケール変換・Unicodeケース処理の要件を分けた
  • ASCIIだけならLC_ALL=Cと引用した文字クラスを使った
  • GNU trの多バイト文字制約を理解し非ASCIIを直接並べていない
  • gawkのロケール、改行、版ごとの差を標本で確認した
  • GNU sedの\Lが移植可能な標準機能ではないと明記した
  • 入力と同じパスへのリダイレクトを避け別出力を作った
  • ID・パス・URL・秘密・監査原本を一括変換していない
  • 衝突・差分・文字コード・改行・メタデータを検証した

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次