ファイルをコピーしてファイル名にパスを追加します。

ファイルをコピーしてファイル名にパスを追加します。

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

ただ考えです。

関連情報