[Linux]大量のファイル名のリネームをコマンド一発で実行するヒント
ファイルのリネームって度々発生します。
数が多くなると面倒でスクリプト組んだりしてたのですが、Linuxコマンド一発でできることを知り、感動しましたのでやり方を残します。
環境
- MacOS 10.13.6
Mac OSにLinuxのsedを入れて使う
今回sedというコマンドを使います。
ただ、Macに標準で入っているsedは、Linuxのsed(GNUのsed)と微妙に挙動が違うので、LinuxのGNU版sedを入れて使います。
# homebrew経由でGNU版sedをインストール brew install gnu-sed # sedコマンドでgsedが使われるように設定(zshの場合) vi ~/.zshrc alias sed="gsed" # 設定を反映 source ~/.zshrc
参考
お題
[field1]_[field2].tsv
というファイル名のデータを
[field2]_[field1].tsv
に直す必要がある、というケース。
具体例
a_20190601.tsv a_20190602.tsv a_20190603.tsv b_20190601.tsv b_20190602.tsv b_20190603.tsv c_20190601.tsv c_20190602.tsv c_20190603.tsv
を
20190601_a.tsv 20190602_a.tsv 20190603_a.tsv 20190601_b.tsv 20190602_b.tsv 20190603_b.tsv 20190601_c.tsv 20190602_c.tsv 20190603_c.tsv
に直す。
数ファイルならまだしも、数百のファイルを一つ一つリネームなんてやってられない。
そんなときに。
一発コマンド
ls、sed、そしてbashをパイプでつなげて使います。
$ ls -1 | sed -r "s/([a-z]+?)_([0-9]+?)\.tsv/mv & \2_\1.tsv/g" | bash
実行結果
1. 下準備
ディレクトリとファイルの作成
※$マークは省略してます
mkdir sed_sample cd sed_sample touch a_20190601.tsv touch a_20190602.tsv touch a_20190603.tsv touch b_20190601.tsv touch b_20190602.tsv touch b_20190603.tsv touch c_20190601.tsv touch c_20190602.tsv touch c_20190603.tsv
2. ファイル確認
ls -1 a_20190601.tsv a_20190602.tsv a_20190603.tsv b_20190601.tsv b_20190602.tsv b_20190603.tsv c_20190601.tsv c_20190602.tsv c_20190603.tsv
3. コマンド実行
ls -1 | sed -r "s/([a-z]+?)_([0-9]+?)\.tsv/mv & \2_\1.tsv/g" | bash
4. 結果確認
ls -1 20190601_a.tsv 20190601_b.tsv 20190601_c.tsv 20190602_a.tsv 20190602_b.tsv 20190602_c.tsv 20190603_a.tsv 20190603_b.tsv 20190603_c.tsv
うまくいきました。
解説
ls -1 | sed -r "s/([a-z]+?)_([0-9]+?)\.tsv/mv & \2_\1.tsv/g" | bash
上記コマンドを分解すると、
1. lsで、カレントディレクトリにあるファイル一覧を出力
2. パイプで1の出力結果を受け取り、sedで置換し、mv [元ファイル名] [新ファイル名]
のテキストを出力
3. パイプで2の出力結果を受け取り、bashで実行
という流れになっています。
sedの解説
sedの要点だけ解説します。
sedは正規表現を使って特定の文字列の抽出・置換が行える便利なコマンドで、
sed "s/置換前/置換後/"
という形式で記述します。
置換前の部分
([a-z]+?)_
: アルファベット小文字1文字以上の文字列を、_(アンダースコア)が出現するまで抽出し、キャプチャ
([0-9]+?)\.tsv
: 数字1文字以上の文字列を、.tsv
が出現するまで抽出し、キャプチャ
置換後の部分
&
: 置換前のテキストをそのまま出力
\2_\1.tsv
: キャプチャした文字列を、2番目のキャプチャ、1番目のキャプチャの順に出力
というように、置換を実行しています。
試しに、1. 下準備をしたあとにsedまでのコマンドを実行してみます。
ls -1 | sed -r "s/([a-z]+?)_([0-9]+?)\.tsv/mv & \2_\1.tsv/g" mv a_20190601.tsv 20190601_a.tsv mv a_20190602.tsv 20190602_a.tsv mv a_20190603.tsv 20190603_a.tsv mv b_20190601.tsv 20190601_b.tsv mv b_20190602.tsv 20190602_b.tsv mv b_20190603.tsv 20190603_b.tsv mv c_20190601.tsv 20190601_c.tsv mv c_20190602.tsv 20190602_c.tsv mv c_20190603.tsv 20190603_c.tsv
置換の結果、上記のような文字列が生成されます。
最後に上記の文字列をパイプでbashコマンドに渡し、Linuxコマンドとして実行することで、一括置換が実現できます。
まとめ
Linuxコマンドと正規表現を使えると面倒な単純作業から解放されるので、使いこなせるようになりたいものです。
今回のコマンドも、sedの正規表現の部分はファイル名の書式によって個別でカスタマイズする必要があるので、頑張って正規表現覚えましょう。
ディスカッション
コメント一覧
まだ、コメントがありません