ファイル リネーム 一括 コマンドで規則が書けないときの手順

ファイル リネーム 一括 コマンドという言葉で調べる人の多くは、置換の書き方そのものではなく、その手前でつまずいています。名前の付け替えを言葉で説明できるのに、パターンの形にすると条件が増えすぎて書けない。撮影日と場所と版数がファイルごとにばらばらで、共通する規則が見当たらない。この型の作業に必要なのは、もっと難しい正規表現ではありません。旧い名前と新しい名前を並べた対応表を作り、それをコマンドに流し込む形へ切り替えることです。

規則で書ける作業と、書けない作業の境目

一括の名前変更は、大きく2つの型に分かれます。境目は単純で、やりたいことを条件の付かない1文で言い切れるかどうかです。

「全部の先頭にある IMG_ を消す」「拡張子を小文字にそろえる」「ハイフンの前後を入れ替える」。ここまでは、対象のどれを見ても処理が同じなので、パターンで書けます。zshに同梱されている zmv でも、for ループと sed の組み合わせでも構いません。

一方で「1枚目から順に、撮影した現場の名前を入れる」「取引先ごとに決まった記号を、こちらが持っている一覧に従って割り当てる」「原稿の見出しを読んで、そこから題名を作る」は、パターンでは書けません。新しい名前を決める材料が、ファイルの名前の中に入っていないためです。材料が外にあるのに、名前の中だけを見る道具で処理しようとすると、条件分岐が延々と増えていきます。

手が止まったときに確かめるのは、書き方の巧拙ではなく材料の在りかです。材料が名前の中にあるならパターンで足ります。名前の外、たとえば表計算のシートや手元のメモや撮影記録の中にあるなら、対応表を通す型に切り替えたほうが早く終わります。

対応表を使う手順は3段に分かれる

対応表の型は、次の3段で組み立てます。1段目でいまの名前を書き出し、2段目で新しい名前の列を作り、3段目でそれを読んで実行します。

やること 使うもの
1 現在の名前を一覧にする find または ls の出力をファイルへ
2 新しい名前の列を作る 表計算、テキストエディタ、スクリプト
3 一覧を読んで名前を変える while readmv

この分け方の利点は、途中で人が目視できることにあります。パターンで書いた1行は、実行するまで結果が見えません。対応表なら、実行の前に3列目まで全部並んだ状態で確認できます。件数が数百を超える作業では、この差が事故の量に直結します。

もう1つの利点は、作業の分担ができることです。名前を決めるのは中身を知っている人、実行するのは手元の環境を持っている人、という分け方ができます。対応表はただのテキストなので、受け渡しに特別な道具が要りません。

いまの名前を、抜けなく書き出す

1段目でよくある失敗は、書き出した一覧に取りこぼしがあることです。並べ替えの結果を目で見て「だいたい合っている」と判断すると、隠しファイルとサブフォルダの中身が落ちます。

cd ~/Pictures/site-a
find . -type f -name '*.jpg' -maxdepth 1 -print0 | sort -z > /tmp/names.txt

-print0sort -z を使うのは、名前に空白や改行が入っていても列がずれないようにするためです。空白を含む名前を改行区切りで扱うと、1つの名前が2件に割れます。この割れ方は件数を数えただけでは気づきにくく、実行してから初めて表面化します。

サブフォルダも対象にするなら -maxdepth 1 を外します。隠しファイルを含めたいなら -name '.*' を足します。逆に、対象から外したいものがあるときは -not -name で先に落としておきます。一覧を作る段階で対象を確定させておくと、あとの2段が単純になります。

書き出したら件数を数えて、Finderで選択したときの件数と突き合わせます。数が合わないなら、この時点で原因を潰しておきます。名前を変えたあとで気づくと、どれが処理済みでどれが未処理かの判別が難しくなります。

件数が合わない原因で多いのは、拡張子の大文字と小文字です。*.jpg の指定では IMG_0001.JPG が対象から外れます。書き出しの段階で -iname に替えるか、大文字の分を別に数えて足しておくと、あとの2段で辻褄が合わなくなる事態を避けられます。

新しい名前は、実行の前に機械で検査する

2段目で作った新しい名前は、目で見て問題がなくても、そのままでは通らないことがあります。macOSがファイル名として受け付けない形が3つあるためです。

  • コロンは名前に使えない。時刻を 10:30 の形で入れようとすると当たる
  • ピリオドで始まる名前は不可視の扱いになり、Finderの一覧から消える
  • 1つの名前の上限は255文字。これはバイト数ではなく文字数で、日本語でも255文字までは作れて、256文字になると受け付けられなくなる

表計算で名前を組み立てると、案件名と日付と版数を連結した時点で上限に近づきます。長い名前だけが失敗し、短い名前は成功するので、途中まで動いて止まる形になります。これがいちばん後始末に手間がかかる失敗です。

そこで、実行の前に対応表そのものを検査します。

awk -F'\t' '{
  if ($2 ~ /:/)        print "コロン: " $2
  if ($2 ~ /^\./)      print "先頭ピリオド: " $2
  if (length($2) > 255) print "長すぎ: " $2
  if (seen[$2]++)      print "新しい名前が重複: " $2
}' map.tsv

4行目の重複の検査は、上の3つより重要です。新しい名前が2件で同じになっていると、あとから実行したほうが先のファイルを黙って上書きします。表計算で連番を振り直したときに起きやすく、実行後に件数が減っていることでようやく気づきます。

対応表を読んで、1件ずつ動かす

3段目は短く書けます。区切りにタブを使い、IFS をタブに固定してから読みます。

while IFS=$'\t' read -r old new; do
  [ -z "$old" ] && continue
  mv -n -- "$old" "$new"
done < map.tsv

mv に付けた -n は、行き先に同じ名前がすでにあるとき、その1件を実行しないという指定です。macOSに入っている mv のマニュアルにも記載があり、上書きの事故をここで止められます。-i にすると1件ずつ確認を求められるので、件数が多いときは -n のほうが向いています。

先頭の -- は、名前がハイフンで始まっているときに、それを命令の指定と取り違えないための区切りです。書き出した一覧に -2026-01.pdf のような名前が混ざっていると、これが無い場合に予期しない動きをします。

空打ちで結果を先に見るなら、mvecho mv に替えて1回流します。画面に出た行をそのまま読めば、どのファイルがどこへ動くかが全件分かります。フォルダとターミナルとAIが同じ窓にある環境なら、この空打ちの出力と対象のフォルダを並べたまま確認できるので、切り替えが要りません。

濁点を含む名前で対応表が当たらない

対応表を作ったのに mv が「そのようなファイルはありません」と返す場合、原因の多くは濁点と半濁点の記録のされ方にあります。

macOSでは、「が」という1文字が、1つの文字として記録されている場合と、「か」と濁点の2つに分かれて記録されている場合があります。画面上はどちらも同じに見えます。現在のAPFSは、この2つの形を同じ名前として扱うので、Finderでもターミナルでも、どちらの形で指定しても目的のファイルに届きます。

問題は、対応表の側です。表計算やメモ帳で打ち直した名前は、ほぼ確実に結合された形になります。それを mv に渡す分には届きますが、書き出した一覧と手で打った一覧を突き合わせる処理、たとえば grepdiff や表計算の照合関数では、この2つは別の文字列として扱われます。目で見て同じなのに一致しない、という状態はここから生まれます。

そろえる方法は決まっています。片方を変換して、比べる前に形を統一します。

iconv -f UTF-8 -t UTF-8-MAC < names.txt > names-nfd.txt
python3 -c 'import sys,unicodedata; sys.stdout.write(unicodedata.normalize("NFC", sys.stdin.read()))' < names.txt

1行目は分解された形へ、2行目は結合された形へそろえる書き方です。どちらへそろえても構いませんが、突き合わせる2つの一覧で同じほうを選ぶ必要があります。

同じ問題は、リポジトリを共有したときにも出ます。Gitの設定にある core.precomposeUnicode は、この形の違いを吸収するための指定で、macOS版のGitがリポジトリを作るときに有効な状態で書き込まれます。macOSとWindowsで同じリポジトリを扱う場面でも、日本語のファイル名を扱う限り同じ論点が残ります。

Windowsから届いたzipは、名前ではなく展開をやり直す

受け取ったzipを開いたら、中のファイル名が読めない記号の並びになっていた。この状態で一括の名前変更をかけようとするのは、順番が逆です。化けているのは名前ではなく、展開のときに使われた文字コードの解釈だからです。

macOSに入っているunzipは、Info-ZIPのUnZip 6.00にAppleが手を入れたものです。unzip -hh で選択肢の一覧を出しても、文字コードを指定する指定は用意されていません。Finderのダブルクリックでも、ditto -x -k でも結果は変わりません。Appleの説明も、受け取ったzipが開けないときは送り直してもらうよう案内しています。

注記: .zipファイルを開けない場合は、Macに解凍した項目を保存するための十分な領域があることを確認してください。.zipファイルをほかの人から受け取った場合は、ファイルに問題があることがあります。その人にファイルをもう一度圧縮して再送するよう依頼してください。 出典: support.apple.com

送り直してもらえない場合は、文字コードを指定して展開し直します。Pythonの標準ライブラリだけで完結します。

import zipfile, os, unicodedata
with zipfile.ZipFile('archive.zip') as z:
    for i in z.infolist():
        name = i.filename if (i.flag_bits & 0x800) else i.filename.encode('cp437').decode('cp932')
        name = unicodedata.normalize('NFC', name)
        dst = os.path.join('out', name)
        os.makedirs(os.path.dirname(dst), exist_ok=True)
        with z.open(i) as src, open(dst, 'wb') as f:
            f.write(src.read())

化けた名前をそのまま一括変換で直そうとすると、対応表の左側にその読めない文字列を貼り付ける必要があり、しかも文字によっては情報が落ちていて元に戻せません。展開の段階からやり直すほうが確実です。

逆向きの対応表を残して、戻せる状態にする

コマンドで名前を変えた場合、Finderの「取り消す」は効きません。戻す手段を用意するかどうかは、実行の前に決めておく必要があります。

用意するのは難しくありません。実行に使った対応表の列を入れ替えたものを、同じフォルダに置いておくだけです。

awk -F'\t' 'BEGIN{OFS="\t"}{print $2, $1}' map.tsv > map-undo.tsv

この1行があるだけで、名前を戻す作業は3段目の再実行になります。日付を入れたファイル名で保存しておけば、数か月後に「この一覧はいつの作業か」を判別できます。

戻す必要が出る場面は、変換の失敗より、決めた規則そのものが後から変わったときのほうが多くなります。取引先の呼び方が変わった、版数の付け方を統一した、といった理由で名前の付け替えは繰り返し発生します。対応表を残しておけば、次の変更は前の対応表を書き換えるところから始められます。

対応表を作る窓と、実行する窓が離れている

ここまでの手順を並べると、実際に時間を使っている場所が見えてきます。名前を書き出すのはターミナル、新しい名前を考えるのは表計算か原稿の中、対象がどれかを確かめるのはフォルダの画面です。3段の手順それぞれが、別の窓に置かれています。

件数が200件を超える作業では、この行き来が本体の作業より長くなります。書き出した一覧を見ながらフォルダの中身を確かめ、表計算に戻って1行直し、またターミナルへ戻る。1回あたりは数秒でも、確認と修正を繰り返す回数だけ積み上がります。ファイル管理の道具に何を求めるかを決めるときは、機能の数ではなく、この往復が何回に減るかで比べたほうが判断を誤りません。

比較の観点は他のファイル管理との比較に整理してあります。フォルダの一覧とターミナルを同じ窓に置いた場合に何ができるかはできることにまとめてあります。手元の環境で試す前に条件を確かめたいときはよくある質問を先に読むと、判断に必要な材料がそろいます。

よくある質問

対応表を使う方法と、zmvのようなパターンの方法は、どちらを覚えるべきですか?

先にパターンの書き方を覚えるのが順当です。名前の中だけで完結する作業は、そのほうが速く終わります。対応表の型は、新しい名前を決める材料がファイルの外にあるとき、つまり撮影記録や取引先の一覧を見ないと名前が決まらないときに必要になります。両方を使い分ける前提で覚えると迷いません。

対応表はどんな形式で作ればよいですか?

タブ区切りのテキストが扱いやすい形です。表計算からタブ区切りで書き出せば、そのまま while IFS=$'\t' read で読めます。カンマ区切りにすると、名前の中にカンマが入っていたときに列がずれます。名前に使われにくい文字を区切りに選ぶのが安全です。

コマンドで名前を変えたあとに、元に戻すことはできますか?

Finderの取り消しは効きません。戻すには、実行前に旧い名前と新しい名前の対応表を保存しておき、列を入れ替えて再実行します。この用意をしていない場合、戻せるのはTime Machineなどのバックアップから復元する経路だけになります。実行前の1手間で復旧の手段が変わります。

名前は合っているはずなのに、ファイルが見つからないと言われます。

濁点や半濁点を含む名前で起きやすい現象です。macOSでは同じ文字が2通りの形で記録されることがあり、画面上は区別が付きません。ファイルシステムはどちらの形でも同じ名前として扱いますが、テキストどうしの照合では別の文字列になります。比べる前に形をそろえてから突き合わせてください。

記事一覧へ戻る