mac ファイル名一括変更に正規表現を使う|zmvとsedの選び分け
mac ファイル名一括変更正規表現、という言葉で調べる人のほとんどは、Finderの一括変更をすでに一度は開いています。そこに検索と置換の欄はあるのに、思っていた書き方が通らない。日付の並びを入れ替えたい、連番の桁をそろえたい、先頭の余計な語だけ落としたい。この種の指定は、Finderの画面では表現できません。必要なのは別の道具ではなく、どの経路なら正規表現が使えるのかという地図と、実行前に空打ちする作法です。
Finderの置換は文字列そのものを見ている
Finderの一括変更は、複数の項目を選んでControlキーを押しながらクリックし、ショートカットメニューの「名称変更」から開きます。開いた先にあるのは3つの動作だけです。
「Finder項目の名前を変更」の下にあるポップアップメニューで、名前のテキストを置き換えるか、名前にテキストを追加するか、名前のフォーマットを変更するかを選択します。 出典: support.apple.com
「テキストを置き換える」は、検索フィールドに入れた文字列をそのまま探して、置換文字列に入れたものへ差し替えます。ここでいう「そのまま」は文字どおりで、アスタリスクを書けばアスタリスクという記号を探しますし、丸括弧を書けば丸括弧を探します。パターンとしては解釈されません。「テキストを追加」は前か後ろに固定の文字列を足すだけ、「フォーマット」は名前のあとにインデックス・カウンタ・日付のどれかを付けるだけです。
つまりFinderで表現できるのは、全ファイルに共通する1つの置換と、機械的な連番付けの2つに限られます。ファイルごとに中身が違う部分を取り出して並べ替える、桁数をそろえる、条件によって処理を分ける、といった指定は入口からありません。ここを何度か試して通らないと感じたなら、それは操作を間違えているのではなく、機能として存在していない範囲に手を伸ばしています。
正規表現が使える経路は3つある
Macの手元で正規表現を使って名前を変える方法は、大きく3つです。追加のインストールが要るかどうかと、書き方の癖が違います。
| 経路 | 追加インストール | 空打ちの指定 | 向いている場面 |
|---|---|---|---|
| zshのzmv | 不要(zshに同梱) | -n |
パターンで取り出して並べ替える |
| forループとsed | 不要(BSD sedが標準) | mv を echo に替える |
名前を条件つきで組み立てる |
| Homebrewのrename | 必要 | -n |
Perlの置換式をそのまま書きたい |
ここで一度確かめておきたいのが、3つ目のrenameです。Linuxの記事に出てくる rename 's/old/new/' *.txt という書き方は、macOSでは動きません。macOSにrenameというコマンドは同梱されていないためです。ターミナルで which rename を打って何も返らないなら、それが理由です。Homebrewで入れれば使えますが、そのために正規表現の一括変更をあきらめる必要はありません。
zmvはzshに最初から入っています。macOSの標準シェルは2019年のCatalina以降zshなので、追加で何かを入れる必要がない、という点がまず大きい。使う前に一度だけ autoload -U zmv を実行すれば、その窓で使えるようになります。毎回打ちたくなければ、この1行を設定ファイルに書いておきます。
zmvは丸括弧が置換用の番号になる
zmvの書き方は、探すパターンと、新しい名前の形を並べるだけです。探す側の丸括弧が順番に番号になり、新しい名前の側で $1、$2 として呼び出せます。
autoload -U zmv
zmv -n '(*).txt' '$1.md'
これは拡張子だけを差し替える書き方です。丸括弧が名前の本体をつかまえ、$1 でそれを呼び戻しています。並べ替えたいときは丸括弧を2つ使います。
zmv -n '(*)-(*).png' '$2-$1.png'
zmv -n '([0-9][0-9][0-9][0-9])(*).pdf' '$1.pdf'
zmv -n '(*)' '${1:l}'
1行目はハイフンの前後を入れ替え、2行目は先頭の4桁の数字だけを残して後ろを落とします。3行目の ${1:l} はzshが持っている変換の書き方で、つかまえた文字列を小文字にそろえます。大文字にそろえるなら ${1:u} です。日付の並びが 2026-09-03 のように区切られているなら、丸括弧を3つ使って $1$2$3 と書けば区切り記号を落とせます。
-n を付けて実行すると、実際には動かさず「こう動かす予定です」という一覧だけが出ます。上の1つ目なら mv -- a.txt a.md のような行が並びます。ここを目で見て、対象と結果が意図どおりなら -n を外して打ち直す。この2段構えが、一括変更でいちばん効く安全策です。件数が多いときは、-n を付けた実行結果をそのままファイルへ書き出しておくと、あとで何を動かしたのかをたどれます。
丸括弧の中身は既定ではシェルのパターンで、正規表現そのものではありません。アスタリスクは任意の文字列、疑問符は任意の1文字、角括弧は文字の範囲を表します。より正規表現に近い書き方をしたいときは -w を付けたり、拡張グロブを有効にした状態の記法を使ったりしますが、実務で必要になる置換のほとんどは、上の4行のかたちで足ります。パターンで表現しきれないと感じたら、無理に一行へ詰め込まず、次のsedへ移るほうが早くなります。
sedを使うときはBSDの癖を先に知る
名前を1つずつ組み立てたいときは、forループとsedの組み合わせになります。ここで引っかかるのは正規表現そのものではなく、macOSに入っているsedがBSD版だという点です。ネット上のサンプルの多くはGNU版を前提に書かれています。
-Eを付けると拡張正規表現になる。これはBSDでもGNUでも同じ\dは使えない。数字は[0-9]と書く\+や\?のようなGNU独自の書き方は通らない- 最短一致(
*?のような書き方)は無い。区切り文字を明示して範囲を切る sed -iは引数を要求する。書き換えを直接行うならsed -i ''と空文字を渡す
スクリーンショットの名前を日付の数字だけに詰める例で書くと、次のような形になります。
for f in "Screen Shot"*.png; do
n=$(printf '%s' "$f" | sed -E 's/^Screen Shot ([0-9]{4})-([0-9]{2})-([0-9]{2}).*/\1\2\3/')
echo mv -n -- "$f" "${n}.png"
done
先頭の echo が空打ちです。表示される行を読んで問題がなければ、echo を消して同じものをもう一度走らせます。echo を消す前に、出力をいったんファイルへ落として件数を数えておくと、対象が想定より多いときに気づけます。1文字の打ち間違いが数百件に一度で広がるのが一括変更なので、確認の一手を挟む価値はここにあります。
名前がぶつかったとき、mvは黙って上書きする
正規表現を使う一括変更でいちばん被害が大きいのは、書き方の失敗ではなく衝突です。パターンを広く書きすぎて、複数のファイルが同じ新しい名前になったとき、mv は何も聞かずに上書きします。警告も確認も出ません。3件が同じ名前に落ちれば、残るのは最後の1件だけです。
防ぎ方は2つあります。mv -n を使うと、行き先にすでにファイルがある場合は何もせずに次へ進みます。ただしこれも黙って進むので、動かなかったファイルが手元に残っていることに後から気づく形になります。mv -i なら1件ずつ確認が入りますが、件数が多いと現実的ではありません。空打ちの段階で新しい名前の一覧を sort | uniq -d に通し、重複が無いことを見てから本番に移るのがいちばん確実です。
もう1つ、Macに特有の落とし穴があります。標準のAPFSは大文字と小文字を区別しない設定で初期化されています。そのため Ab.txt があるフォルダで別のファイルを ab.txt へ変えると、衝突として扱われて既存のファイルが消えます。しかも残る名前は元の Ab.txt のままで、指定した小文字にはなりません。名前を小文字にそろえる一括変更は、この理由で件数が合わなくなることがあります。
日本語のファイル名が当たらないのは字の形が2種類あるから
パターンは正しいのに、日本語を含むファイルの一部だけが対象から漏れる。この症状の原因は、ほぼ正規化の違いです。「ガ」のような濁点付きの文字には、1文字として持つ形と、「カ」と濁点の2文字に分けて持つ形の2種類があります。画面上はどちらも同じに見えます。
古いHFS Plusで作られたファイルや、そこから引き継いだバックアップの中身は、分けて持つ形になっていることがあります。同じ「ガイド」という名前でも、片方は9文字、もう片方は11文字として扱われます。ここへ、キーボードから打った1文字の形のパターンを当てても、分けて持つ側には当たりません。2件あるはずのファイルが1件しか出てこない、という数え違いはこれで起きます。
さらに紛らわしいのは、シェルによって見え方が変わる点です。zshで *.txt を展開したときに返る名前は1文字の形にそろっており、同じフォルダでbashを使うと保存されているままの形が返ってきます。手で打つと通るのに、#!/bin/bash と書いたスクリプトに入れた途端に対象が減る、という現象はここから来ます。対象が合わないときは、ls | grep 'ガイド' | wc -l の件数と、フォルダにある実際の件数を突き合わせてみると、原因がパターンなのか字の形なのかを切り分けられます。
空白と記号で壊れるのは決まった3か所
一括変更のスクリプトが途中で止まる原因は、正規表現より手前にあることが多くあります。壊れる場所はだいたい決まっています。
- 変数を引用符で囲んでいない。
mv $f $nは空白の位置で引数が割れます。mv -- "$f" "$n"と書きます - ハイフンで始まる名前をオプションとして読まれている。コマンドとファイル名のあいだに
--を挟むと、そこから先は名前として扱われます lsの出力をループに渡している。for f in $(ls)は空白と改行で割れます。for f in *.pngのようにパターンを直接書きます
find の結果を渡すときは、find . -name '*.png' -print0 | xargs -0 -n1 のように区切りをヌル文字にすると、空白を含む名前でも割れません。名前そのものに使えない文字もあります。コロンはファイル名に含められず、ピリオドで始まる名前も作れません。置換の結果としてコロンが入る書き方をしていると、その行だけが失敗します。
窓の行き来が残っているなら、詰まりは書き方ではない
正規表現を覚えても短くならない工程があります。フォルダの窓で対象を見て、ターミナルで空打ちして、結果を確かめるためにフォルダへ戻る。この往復です。1回あたりは十数秒でも、空打ちと本番で最低2往復、失敗すればさらに増えます。
ここで効いてくるのが、フォルダとターミナルとAIが同じ窓にあるという配置です。一覧とコマンド入力が同じ作業ディレクトリを共有していれば、パスを写す動作と窓を切り替える動作が工程から消えます。パターンを組み立てる作業をAIに投げるにしても、対象のファイル名がその場にある状態と、別の窓から貼り直す状態では手数が変わります。
この配置で何ができるのかはできることにまとまっており、2画面型やターミナル常駐型など別の課題を解いている道具との違いは他のファイル管理との比較で並べて見られます。費用の考え方は料金にあります。
道具を替える前に、まず自分の一括変更が何回の往復で終わっているかを数えるのが先です。1往復で済んでいるなら、この記事のzmvの4行を覚えるだけで足ります。空打ちのたびに窓を切り替えているなら、直すべきなのは正規表現の書き方ではなく、道具の置き場所です。
よくある質問
Finderの一括変更で正規表現を使う方法はありますか?
ありません。Finderの「テキストを置き換える」は入力した文字列をそのまま探す仕組みで、アスタリスクや丸括弧もただの記号として扱われます。パターンでの置換が必要なら、zshに同梱されているzmvか、forループとsedの組み合わせに移る必要があります。どちらも追加のインストールは要りません。
renameコマンドが見つからないと出るのはなぜですか?
macOSにrenameというコマンドが同梱されていないためです。Linux向けの記事に出てくる rename 's/old/new/' *.txt はそのままでは動きません。Homebrewで入れれば使えますが、zmvで同じことができるので、そのためだけに導入する必要はありません。
一括変更を実行する前に結果を確かめる方法はありますか?
zmvなら -n を付けて実行すると、動かす予定の一覧だけが表示されます。forループとsedの場合は、mv の手前に echo を置くと同じ確認ができます。あわせて新しい名前の一覧を sort | uniq -d に通し、重複が無いことを見てから本番に移ると、上書きの事故を防げます。
一括変更で消えたファイルは元に戻せますか?
mv で上書きされたファイルは、ゴミ箱を経由しないため元には戻りません。Time Machineのバックアップか、iCloud DriveやDropboxの版管理から拾い直すことになります。Finderの一括変更であればCommand+Zで直前の操作を取り消せますが、ターミナルからの変更には取り消しの仕組みがないので、空打ちで確かめる手順のほうが現実的な備えになります。