ちょっと話題の記事

大量のファイルをシェルのコマンドで一括リネームする

2015.11.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

大量のファイルを一括でリネームする場合、もしリネーム手順が簡素であれば、専用のスクリプトを書いたり、リネーム用のツールを使ったりせずともワンライナーで処理することができます。

前提

  1. リネーム対象のファイルを一つのフォルダにまとめている。
  2. 上記フォルダにリネーム対象ファイル以外の余分なファイルは含まれていない。
  3. 上記フォルダを作業ディレクトリとする。
  4. 作業は全て Mac OS X で行う。

目次

  1. 元のファイル名に文字を加える
  2. 元のファイル名に昇順で数字を追加する
  3. 元のファイル名に日付を加える

Case 1. 元のファイル名に文字を加える

対象ファイル

現在のファイル名 リネーム後のファイル名
001.txt 001_document.md
002.txt 002_document.md
003.txt 003_document.md
004.txt 004_document.md
005.txt 005_document.md
…… ……
999.txt 999_document.md

コマンド

$ ls | sed -e s/\.txt// | awk '{print $1 ".txt " $1 "_document.md"}' | xargs -n 2 mv

戦略について

まず前提として、ファイルのリネームを行うには、 xargs -n 2 mv にパイプで 元ファイル名 リネーム後のファイル名 のようなフォーマットの文字列を渡せば OK です。

$ ls
before.txt

$ echo "before.txt after.txt"
before.txt after.txt

$ echo "before.txt after.txt" | xargs -n 2 mv

$ ls
after.txt

この文字列が複数行ある場合、 xargs -n 2 mv は1行ずつ順次処理します。

$ ls
1.txt 2.txt

$ echo "1.txt 11.txt\n2.txt 22.txt"
1.txt 11.txt
2.txt 22.txt

$ echo "1.txt 11.txt\n2.txt 22.txt" | xargs -n 2 mv

$ ls
11.txt 22.txt

ならば、今回の目標は以下のような複数行の文字列を作成し、 xargs -n 2 mv にパイプで食わせることです。

001.txt 001_document.md
002.txt 002_document.md
003.txt 003_document.md
004.txt 004_document.md
005.txt 005_document.md
(中略)
999.txt 999_document.md

まず最初に、lssed を使って、フォルダ内に含まれる 拡張子を除く ファイル名の一覧を作ります。

$ ls | sed -e s/\.txt//
001
002
003
004
005
(中略)
999

次に awk を使って、ファイル名をマッピング文字列に変換します。

$ ls | sed -e s/\.txt// | awk '{print $1 ".txt " $1 "_document.md"}'
001.txt 001_document.md
002.txt 002_document.md
003.txt 003_document.md
004.txt 004_document.md
005.txt 005_document.md
(中略)
999.txt 999_document.md

※ これらの処理を一つの awk 命令にまとめることもできます。しかし便利な反面、学習コストが大きいため、今回は awk の使用を最小限にとどめています。

これで目標としていた文字列が完成したので、あとは xargs -n 2 mv に食わせれば OK です。

$ ls | sed -e s/\.txt// | awk '{print $1 ".txt " $1 "_document.md"}' | xargs -n 2 mv

$ ls
000_document.md  200_document.md  400_document.md  600_document.md  800_document.md
001_document.md  201_document.md  401_document.md  601_document.md  801_document.md
002_document.md  202_document.md  402_document.md  602_document.md  802_document.md
003_document.md  203_document.md  403_document.md  603_document.md  803_document.md
004_document.md  204_document.md  404_document.md  604_document.md  804_document.md
005_document.md  205_document.md  405_document.md  605_document.md  805_document.md
………
…

ファイルの一括リネームが完了しました。

Case 2. 元のファイル名に昇順で数字を追加する

対象ファイル

現在のファイル名 リネーム後のファイル名
a.txt 01_a.txt
b.txt 02_b.txt
c.txt 03_c.txt
d.txt 04_d.txt
e.txt 05_e.txt
…… ……
z.txt 26_z.txt

コマンド

$ ls | nl | awk '{ printf("%s %02d_%s\n", $2, $1, $2) }' | xargx -n 2 mv

戦略について

基本的には、1. 元のファイル名に文字を加えると同じ戦略です。 xargs -n 2 mv にマッピング用の文字列を食わせます。

今回の目標になる文字列は以下のとおりです。

a.txt 01_a.txt
b.txt 02_b.txt
c.txt 03_c.txt
d.txt 04_d.txt
e.txt 05_e.txt
(中略)
z.txt 26_z.txt

1. 元のファイル名に文字を加えると異なるのは、あたらしくファイルのナンバリングを行う部分です。

まず、ls | nl で行番号つきのファイル一覧を表示します。

$ ls | nl
     1  a.txt
     2  b.txt
     3  c.txt
     4  d.txt
     5  e.txt
     (中略)
    26  z.txt

これらは awk2つの引数として食わせることができます。ここでは、第一引数($1)が行番号、第二引数($2)が元のファイル名になります。

これで必要な情報が揃ったため、 awk でマッピング用の文字列に整形します。

$ ls | nl | awk '{ printf("%s %02d_%s\n", $2, $1, $2) }'
a.txt 01_a.txt
b.txt 02_b.txt
c.txt 03_c.txt
d.txt 04_d.txt
e.txt 05_e.txt
(中略)
z.txt 26_z.txt

今回は、数字をゼロ埋めする必要が合ったため printf を使いました。Cファミリーの言語を使ったことがある方にはおなじみの関数です。

これで目標としていたマッピング文字列が完成しました。あとは xargs -n 2 mv に食わせれば完了です。

$ ls | nl | awk '{ printf("%s %02d_%s\n", $2, $1, $2) }' | xargx -n 2 mv

$ ls
01_a.txt 03_c.txt 05_e.txt 07_g.txt 09_i.txt 11_k.txt 13_m.txt 15_o.txt 17_q.txt 19_s.txt 21_u.txt 23_w.txt 25_y.txt
02_b.txt 04_d.txt 06_f.txt 08_h.txt 10_j.txt 12_l.txt 14_n.txt 16_p.txt 18_r.txt 20_t.txt 22_v.txt 24_x.txt 26_z.txt

ファイルの一括リネームが完了しました。

Case 3. 元のファイル名に日付を加える

対象ファイル

現在のファイル名 ファイルの作成日 リネーム後のファイル名
a.txt 2月11日 0211_a.txt
b.txt 2月12日 0212_b.txt
c.txt 2月13日 0213_c.txt
d.txt 3月20日 0320_d.txt
e.txt 3月21日 0321_e.txt
…… ……
z.txt 5月1日 0501_z.txt

コマンド

$ ls -l | grep -v total | awk '{ printf("%s %02d%02d_%s\n", $9, $6, $7, $9) }' | xargs -n 2 mv

戦略について

1. 元のファイル名に文字を加える2. 元のファイル名に昇順で数字を追加するで使った小技を用いた複合的なアプローチです。

grep -v totalls -l の total 行を取り除いています。ls -l の実行結果が英語以外だったりすると、このワンライナーはうまく動作しないかもしれません。

1. や 2. を読んでくださった方にとっては説明が冗長になってしまうため、詳しい解説はしませんが、今までどおり ls -l の結果を元にマッピング用の文字列を生成して xargs -n 2 mv に食わせているだけです。

まとめ

簡単な一括リネームには xargs -n 2 mv を活用しましょう。
ではまた!