Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

スペース文字が入ったファイル名をxargsを使って一括変換したいとき、-0オプションを使うといいかも

シェルスクリプトでファイル名を一括変換したり、ファイル移動したりしたいが
該当ファイルにスペースが入っていてxargsがうまく動かない場合があります。
そんな時は、ヌル文字をデリミターにつかう"-0"オプションが使えるかもしれません。

実際のところ

こんな風に、iPhoneでとった写真が入ったディレクトリがあるとします。
これをimageNUM.jpgといった感じに変更するケースを考えます。

$ ls -1 iOS* 
iOS の画像 (1).jpg
iOS の画像 (2).jpg
iOS の画像.jpg
$ find iOS*  | sed "p; s/iOS の画像/image/"
iOS の画像 (1).jpg
image (1).jpg
iOS の画像 (2).jpg
image (2).jpg
iOS の画像.jpg
image.jpg

xargsには指定行を引数にとるオプションがあるので、これを使ってデリミターを改行としてやれば良さそうに感じます。
が……残念ながら、ファイル名に含まれるスペースが悪さをします。

 $ find iOS*  | sed "p; s/iOS の画像 /image/" | xargs -E '\n' -n2 mv
mv: rename iOS to の画像: No such file or directory
mv: rename (1).jpg to image(1).jpg: No such file or directory
mv: rename iOS to の画像: No such file or directory
mv: rename (2).jpg to image(2).jpg: No such file or directory
mv: rename iOS to の画像.jpg: No such file or directory
mv: rename iOS to の画像.jpg: No such file or directory

ここで、ヌル文字をデリミターにする"-0"オプションです。
まず下準備として、改行をヌル文字に変えてみましょう。
変換対象の改行がヌル文字になっているのが確認できます。

$ find iOS*  | sed "p; s/iOS\ の画像/image/" | tr '\n' '\0' | xxd 
00000000: 694f 5320 e381 aee7 94bb e583 8f20 2832  iOS ......... (2
00000010: 292e 6a70 6700 696d 6167 6520 2832 292e  ).jpg.image (2).
//(ry

あとは、"-n"オプションと"-0"オプションをつかって、mvコマンドに渡してあげるだけです。

$ find iOS*  | sed "p; s/iOS\ の画像/image/" | tr '\n' '\0' | xargs -0 -n2 mv

実行結果をみれば、意図通りファイル名が変更されています。

$ ls
image (2).jpg	image (1).jpg	image.jpg

……今回は3個程度なので有難味が薄いですが……数が多い時は絶対児童がしたほうがいいです。
findは更新時刻の取得もできたりするので、視察場所毎にリネームしたりとか応用は色々と考えられます。