for file in $(find . -depth -name '*rier*'); do
mv $file $(echo $file | sed -e 's/rier/river/');
done
Это может сделать простой цикл for
с расширением параметров для извлечения различных элементов:
for file in */*/*.mp3;
do
artist=${file%%/*}
rest=${file#*/}
album=${rest%%/*}
track=${rest#*/*}
cp -- "$file" /flash/drive/"${artist}-${album}-${track}"
done
Первое расширение удаляет все, начиная с конца файла и заканчивая первой прямой -косой чертой --, генерирующей исполнителя.
Второе расширение удаляет начальные символы до первой прямой -косой черты --и через нее, удаляя исполнителя с пути.
Третье расширение похоже на первое, удаляя имя файла из оставшегося пути, оставляя альбом.
Четвертое расширение похоже на второе, убирая альбом, оставляя только имя файла.
Затем мы соединяем все это вместе с помощью тире и копируем в желаемый путь /flash/drive.
Я считаю плохой практикой манипулировать несколькими строками с расширением параметров оболочки и назначением переменных.
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
Использование 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
уже существует, выводится сообщение об этом, иначе файл копируется.
Связанные:
Мне было любопытно, смогу ли я найти решение, которое достигает двух целей:
Основываясь на прекрасном ответе @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
Просто мысль.