背景
その昔iTunesなどでCDからPCに取り込んだmp3ファイルに対して、Music Source Separationやったりして遊びたいときってありますよね。
ただ、曲名って複数単語だとスペースが入っていたり、アポストロフィとしてシングルクォートが含まれていたり(No Man's Landのような)で、コマンドライン上で使うにはあまりありがたくない文字列である場合も多いです。
とりあえず、あとあと扱いやすくするために、これらの面倒な文字を_に置換してしまいたい、というのが今回の動機です。
私が試したケースでいうと、タイトルのようにスペースとシングルクォートだけで事足りたのですが、それ以外の場合があれば適宜コマンド上で置換対象とする文字を増やしてもらえればと思います。
(2020/09/09追記)MacまたはLinuxではrenameコマンドでよかった。Macの場合、brewでrenameをインストールしてから実行する。
brew install rename
ls *.mp3 | rename "s/[\ \']/_/g"
(追記ここまで)
コマンド
ls *.mp3 | awk '{gsub(/\ /,"\\ ");gsub(/'\''/,"\\'\''");print;gsub(/[\ '\'']/,"_");gsub(/\\/,"");print}' | xargs -n 2 mv
処理の流れ
ちょっとだけ内容を解説します。
1. リネームさせたいファイル名を抽出する
ls *.mp3 の部分です。今回は拡張子mp3のファイルに限定していますが、ここは任意です。
2. 変更前のファイル名と変更後のファイル名を出力する
awk '{ 〜〜 }'の個所です。何やってるのかわからないところかと思います。
ここでは、パイプ経由で標準入力に与えられた行(ファイル名)を「編集して出力」を2回行っています。
たとえば、ho ge'ho ge.mp3という半角スペースとシングルクォートを含むファイル名があったとします。awkへの入力に流れてきたときの流れを見やすく表現してみましょう。
{ # ho ge'ho ge.mp3
gsub(/\ /,"\\ "); # ho\ ge'ho\ ge.mp3
gsub(/'\''/,"\\'\''"); # ho\ ge\'ho\ ge.mp3
print; # ↑を出力
gsub(/[\ '\'']/,"_"); # ho\_ge\_ho\_ge.mp3
gsub(/\\/,""); # ho_ge_ho_ge.mp3
print # ↑を出力
}
処理自体は単純なのですが、エスケープまみれなせいで見づらくなってますね。
awkでは、半角スペースやバックスラッシュは\を前につけるだけでエスケープできるのですが、シングルクォートは'\''と、バックスラッシュを前に付けた上でさらにシングルクォートで囲む、ということをしないといけないようです。
3. awkの出力をmvの引数に渡して実行する
上記awkの処理では、mvに渡す「変更前のファイル名」と「変更後のファイル名」をそれぞれ出力しました。それらをmvの2つの引数に渡すにはxargsを使います。
xargs -n 2 <cmd>
で、前2つの出力を<cmd>の引数として渡せます。つまり、この場合は最終的に
mv ho\ ge\'ho\ ge.mp3 ho_ge_ho_ge.mp3
というコマンドが実行されることになります。
おわりに
もっといいやり方ないんかいな… あったので追記した。