Копирование файлов Добавление пути к файлу

for file in $(find . -depth -name '*rier*'); do 
  mv $file $(echo $file | sed -e 's/rier/river/');
done
1
08.07.2018, 18:09
4 ответа

Это может сделать простой цикл forс расширением параметров для извлечения различных элементов:

for file in */*/*.mp3;
do
  artist=${file%%/*}
  rest=${file#*/}
  album=${rest%%/*}
  track=${rest#*/*}
  cp -- "$file" /flash/drive/"${artist}-${album}-${track}"
done

Первое расширение удаляет все, начиная с конца файла и заканчивая первой прямой -косой чертой --, генерирующей исполнителя.

Второе расширение удаляет начальные символы до первой прямой -косой черты --и через нее, удаляя исполнителя с пути.

Третье расширение похоже на первое, удаляя имя файла из оставшегося пути, оставляя альбом.

Четвертое расширение похоже на второе, убирая альбом, оставляя только имя файла.

Затем мы соединяем все это вместе с помощью тире и копируем в желаемый путь /flash/drive.

2
27.01.2020, 23:18

Я считаю плохой практикой манипулировать несколькими строками с расширением параметров оболочки и назначением переменных.

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
1
27.01.2020, 23:18

Использование 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. Для их пакетов выполняется короткий сценарий. Пара параметров сценария — $mp3dirи $destdir, а остальные — пути к файлам MP3.

Сценарий выбирает два имени каталога из первых двух аргументов командной строки, а затем перебирает остальные аргументы, создавая путь назначения как $destдля каждого файла MP3. Это делается с помощью подстановки параметра bash, которая заменяет все косые черты в имени пути на тире после удаления начального бита $mp3dirимени пути.

Если $destуже существует, выводится сообщение об этом, иначе файл копируется.

Связанные:

1
27.01.2020, 23:18

Фон

Мне было любопытно, смогу ли я найти решение, которое достигает двух целей:

  • легче читать
  • легче отлаживать

Основываясь на прекрасном ответе @kusalananda на другие вопросы и ответы U&L под названием:Понимание опции -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/..и переформулирует имя так, чтобы оно имело тире(-)везде, где есть косая черта(/).

ПРИМЕЧАНИЕ:Я добавил 2 операции в sed.Первый удаляет любой префикс ./, который может существовать, если вы используете find....вместо find Artist*...

Альтернативы?

Я думаю, что делать это с помощью findи cpвсе же не идеальное решение. Я тоже поддерживаю каталоги файлов MP3, и я думаю, что делать что-то подобное с rsyncи с помощью предоставленных вами списков rsyncможет быть более полезной реализацией, в долгосрочной перспективе, поскольку вы можете использовать ее для обновления, а не для повторного -копировать каждый раз, когда вы запускаете его.

$ man rsync
...
        --files-from=FILE       read list of source-file names from FILE

Просто мысль.

0
27.01.2020, 23:18

Теги

Похожие вопросы