Как извлечь имя файла из двух частей, превратив одно в каталог, а другое в него? - PullRequest
1 голос
/ 14 октября 2019

Я пытаюсь отсортировать все mp3-файлы по исполнителю и имени. На данный момент они в одном гигантском имени файла. Например, Artist - Song name.mp3 Я хочу преобразовать это в Artist / Song name.mp3

Вот что я пробовал до сих пор. В этом случае я использовал тестовый файл с именем "hi \ - \ hey":

#!/bin/bash
# filters by all .mp3 extensions in the current working directory 
for f in *.mp3; do
# extract artist and song name and remove spaces
        artist=${f%  -*}
        song=${f#*-  }
#make directory with the extracted artist name and move + rename the file into the directory
        mkdir -p $artist
        mv $f $artist/$song;
done

По какой-то причине он создает каталог с именем песни вместо исполнителя в дополнение к загрузкеошибки:

mv: cannot move 'hey.mp3' to a subdirectory of itself, 'hey.mp3/hey.mp3'
mv: cannot stat 'hi': No such file or directory
mv: cannot stat '-': No such file or directory
mv: 'hey.mp3/hi' and 'hey.mp3/hi' are the same file
mv: cannot stat '-': No such file or directory

Ответы [ 3 ]

1 голос
/ 14 октября 2019

Безусловно, самый простой способ сделать это - использовать rename aka Perl rename.

По сути, вы хотите заменить последовательность SPACE-DASH-SPACE разделителем каталогов прямой косой черты, поэтомукоманда:

rename --dry-run -p 's| - |/|' *mp3

Пример вывода

'Artist - Song name.mp3' would be renamed to 'Artist/Song name.mp3'
'Artist B - Song name 2.mp3' would be renamed to 'Artist B/Song name 2.mp3'

Если это выглядит правильно, просто удалите --dry-run и снова запустите его по-настоящему. Преимущества использования rename заключаются в следующем:

  • он может выполнить пробный прогон для проверки перед тем, как запустить на реальном
  • , он создаст все необходимые каталоги с опцией -p
  • он не будет блокировать (перезаписывать) файлы без предупреждения
  • у вас есть все возможности Perl, доступные вам, и вы можете сделать ваше переименование настолько сложным, насколько вы пожелаете.

Обратите внимание, что вы можете установить на macOS с homebrew :

brew install rename
0 голосов
/ 14 октября 2019

Вы можете попробовать это.

#!/usr/local/bin/bash
for f in *.mp3
do
artist=`echo $f | awk '{print $1}' FS=-`
song=`echo $f | awk '{print $2}' FS=-`
mkdir -p $artist
mv $artist-$song $song
mv $song ./$artist
done

здесь я использую два переменных исполнителя и песню. так как имя вашего тестового файла "hi \ - \ hey", поэтому я изменяю разделитель awk на "-" для хранения переменной в соответствии с ним.

нам не нужно использовать awk..by с помощью параметра bashрасширение .... это работает.

#!/usr/local/bin/bash
for f in *.mp3
do
artist=`echo ${f%-*}`
song=`echo ${f#*-}`
mkdir -p $artist
mv $artist-$song $song
mv $song ./$artist
done
0 голосов
/ 14 октября 2019

Предполагая, что файлов много, возможно, гораздо быстрее сделать это, используя конвейеры вместо цикла for. Это дает дополнительное преимущество, заключающееся в избежании сложного bash -специфического синтаксиса и использовании вместо этого основных программ командной строки unix / linux.

find *-*.mp3 |
  sed 's,\([^-]\+\)\s*-\s*\(.*\),mkdir -p "\1"; mv "&" "\1"/"\2",' |
  bash

Объяснение:

Это find для поиска всехфайлы, соответствующие - .mp3 в текущем каталоге.

Эта команда sed заменяет каждую строку на строку команды, например:

aaa - bbb.mp3
->
mkdir -p "aaa"; mv "aaa - bbb.mp3" "aaa"/"bbb.mp3"

bashкоманда запускает каждую из этих командных строк.

...