mp3ファイルをディレクトリからフラッシュドライブにコピーしたいです。これは次のディレクトリ構造に保存されますArtist/Album/Track.mp3
。私の車のmp3プレーヤーが不都合なので、フラッシュドライブのルートディレクトリにファイル名がArtist-Album-Track.mp3
。
答え1
for
パラメータ拡張を介してさまざまな要素を抽出する単純なループがこれを行います。
for file in */*/*.mp3;
do
artist=${file%%/*}
rest=${file#*/}
album=${rest%%/*}
track=${rest#*/*}
cp -- "$file" /flash/drive/"${artist}-${album}-${track}"
done
最初の拡張は、ファイルの終わりから最初のスラッシュ(作成されたアーティスト)まですべてを削除します。
2番目の拡張パックが削除されました。先頭最初のスラッシュまでの文字 - パスからアーティストを削除します。
3番目の拡張は最初の拡張と似ており、残りのパスからファイル名を削除してアルバムを残します。
4番目の拡張パックは2番目の拡張パックに似ており、アルバムを削除してファイル名のみを残します。
次に、それらをすべて一緒にダッシュし、目的の/flash/driveパスに接続します。
答え2
次の場所でファイルを使用してfind
コピーする:bash
$mp3dir
$destdir
mp3dir="$HOME/my_music"
destdir="/mnt/my_mp3_player"
find "$mp3dir" -type f -name '*.mp3' -exec bash -c '
mp3dir=$1; destdir=$2; shift 2
for pathname do
dest=${pathname#$mp3dir/}
dest="$destdir/${dest//\//-}"
if [ -f "$dest" ]; then
printf "%s exist, skipping %s\n" "$dest" "$pathname" >&2
else
cp "$pathname" "$dest"
fi
done' bash "$mp3dir" "$destdir" {} +
$mp3dir
で始まる名前を見つけます.mp3
。このようなバッチでは、短いスクリプトが実行されます。このスクリプトの2つのパラメータは$mp3dir
、$destdir
残りのパラメータはMP3ファイルのパス名です。
スクリプトは、最初の2つのコマンドライン引数から2つのディレクトリ名を選択し、残りの引数を繰り返して$dest
各MP3ファイルの宛先パス名を作成します。これはbash
、パス名の最初のビットを削除した後、パス名のすべてのスラッシュをダッシュに置き換えるパラメータ置換を使用して行われます。$mp3dir
すでに存在する場合は、$dest
このファイルのメッセージが印刷され、それ以外の場合はコピーされます。
関連:
答え3
操作は悪い習慣だと思います。複数の文字列シェルパラメータ拡張と変数割り当てがあります。
root_dir="~/songs"
for fn in */*/*.mp3
do
cp -v "$fn" "${root_dir}/${fn////-}" # replace all slashes by dashes
done
出力:
~/songs/Artist-Album-Track.mp3
答え4
背景
2つの目標を達成するソリューションを策定することが可能かどうか疑問に思います。
- 読みやすい
- デバッグする方が簡単
次のタイトルの他のU&L Q&Aに対する@kusalanandaの素晴らしい回答に基づいています。-exec オプションについてfind
、私の考えでは、あなたの問題を解決する方法を見つけたと思います。
まず、私の例のディレクトリ構造は、あなたのディレクトリ構造を模倣しています。
$ mkdir -p Artist{1..5}/Album{1..5}
$ touch Artist{1..5}/Album{1..5}/Track{1..5}.mp3
結果は次のとおりです。
$ find Artist* -type f | head
Artist1/Album1/Track1.mp3
Artist1/Album1/Track2.mp3
Artist1/Album1/Track3.mp3
Artist1/Album1/Track4.mp3
Artist1/Album1/Track5.mp3
Artist1/Album2/Track1.mp3
Artist1/Album2/Track2.mp3
Artist1/Album2/Track3.mp3
Artist1/Album2/Track4.mp3
Artist1/Album2/Track5.mp3
mp3ファイルを次の場所にコピーします./targetDir
。
$ find . -type f -name '*.mp3' -exec sh -c \
'cp {} targetDir/$(echo "{}" | sed "s#\./##g;s#/#-#g")' \;
結果は次のとおりです。
$ ls targetDir/ | head
Artist1-Album1-Track1.mp3
Artist1-Album1-Track2.mp3
Artist1-Album1-Track3.mp3
Artist1-Album1-Track4.mp3
Artist1-Album1-Track5.mp3
Artist1-Album2-Track1.mp3
Artist1-Album2-Track2.mp3
Artist1-Album2-Track3.mp3
Artist1-Album2-Track4.mp3
Artist1-Album2-Track5.mp3
cp ...
私はコマンドを最初にラップしてジョブをecho
送信する前に出力を確認できるので、このアプローチが好きです。
$ find . -type f -name '*.mp3' -exec sh -c \
'echo "cp {} targetDir/$(echo "{}" | sed "s#\./##g;s#/#-#g")"' \;
cp ./Artist1/Album1/Track1.mp3 targetDir/Artist1-Album1-Track1.mp3
cp ./Artist1/Album1/Track2.mp3 targetDir/Artist1-Album1-Track2.mp3
cp ./Artist1/Album1/Track3.mp3 targetDir/Artist1-Album1-Track3.mp3
cp ./Artist1/Album1/Track4.mp3 targetDir/Artist1-Album1-Track4.mp3
cp ./Artist1/Album1/Track5.mp3 targetDir/Artist1-Album1-Track5.mp3
cp ./Artist1/Album2/Track1.mp3 targetDir/Artist1-Album2-Track1.mp3
cp ./Artist1/Album2/Track2.mp3 targetDir/Artist1-Album2-Track2.mp3
cp ./Artist1/Album2/Track3.mp3 targetDir/Artist1-Album2-Track3.mp3
cp ./Artist1/Album2/Track4.mp3 targetDir/Artist1-Album2-Track4.mp3
...
どのように動作しますか?
ソリューションは、次のシェルコマンドの出力を取得したfind
後に実行されます。
cp {} targetDir/$(echo "{}" | sed "s#\./##g;s#/#-#g")'
cp
これにより、ファイルがからArtist../Album../Track..
に変更され、targetDir/..
名前が書き換えられ、-
スラッシュ()がある場所にダッシュ()が存在します/
。
メモ:代わりに使用する場合は、存在する可能性のあるプレフィックスをsed
最初に削除することをお勧めします。./
find . ...
find Artist* ..
代替?
私はこれを使用しfind
て実行することがcp
まだ理想的な解決策ではないと思います。私はまた、MP3ファイルのディレクトリを管理しており、提供されたrsync
リストを介して同様の操作を実行することは、実行するrsync
たびにコピーするのではなく更新するために使用できるため、長期的にはより便利な実装になると思います。
$ man rsync
...
--files-from=FILE read list of source-file names from FILE
ただ考えです。