find で見つけた mp3 ファイルを一か所にまとめて移動する方法【スペース・日本語ファイル名にも対応】


音楽ファイルや録音データなど、さまざまな `.mp3` ファイルをディレクトリ構造を無視して一か所にまとめておきたい。そんなときに便利なのが `find` コマンドと `mv` コマンドの組み合わせです。
ただし、ファイル名に半角スペースや日本語・記号が含まれている場合は要注意。そのまま `for` 文などで処理すると、意図しない分割が起きて失敗してしまいます。
今回は、筆者が実際に直面したエラー例を紹介しつつ、安全に `.mp3` ファイルを一か所に移動させる方法をご紹介します。
失敗例:for文+find の出力がスペースに弱い
for f in $(find . -name "*.mp3"); do mv "$f" ./music/ done
この書き方では、ファイル名にスペースや日本語が含まれていると分割されてしまい、以下のようなエラーがずらりと並びます。
mv: `Classic/Classic' を stat できません: そのようなファイルやディレクトリはありません mv: `#13' を stat できません: そのようなファイルやディレクトリはありません
正しい方法:-print0
と read -d ''
を使おう
mkdir -p ./music find /mnt/main/share/0common/00_swaps/iTunes-Share/Music/EMI\ Classic/ -type f -name "*.mp3" -print0 | \ while IFS= read -r -d '' file; do echo "$file" mv "$file" ./music/ done
-
-print0
:ファイル名の区切りを NULL(\0
)に -
-d ''
:NULL 区切りで正しく読み取る -
"$file"
:ファイル名をダブルクォートで囲み、分割されるのを防ぐ -
IFS=
:余計な区切り(スペースや改行)を無効化
同名ファイルがあるときに安全に避ける方法
同じファイル名がすでに移動先に存在する場合、mv
で上書きされてしまいます。これを防ぐために、次のようなリネーム付きスクリプトも便利です。
mkdir -p ./music find . -type f -iname "*.mp3" -print0 | while IFS= read -r -d '' file; do base=$(basename "$file") dest="./music/$base" if [[ -e "$dest" ]]; then i=1 while [[ -e "./music/${i}_$base" ]]; do ((i++)) done dest="./music/${i}_$base" fi mv "$file" "$dest" done
まとめ
-
find
+mv
は非常に強力ですが、スペースや特殊文字の罠に注意が必要です。 -
-print0
/read -d ''
という構文は一見マニアックですが、安全性と汎用性を両立できる必須スキルです。 -
この記事の方法を覚えておけば、画像・音声・PDFなどのファイル整理にも応用できます。