bash изменить абсолютный путь в файле построчно для создания скрипта - PullRequest
0 голосов
/ 01 ноября 2018

Я пытаюсь создать bash-скрипт на основе входного файла (list.txt). Входной файл содержит список файлов с абсолютным путем. Выводом должен быть скрипт bash (move.sh), который перемещает файлы в другое место, сохраняет структуру папок, но перед этим немного изменяет имя целевой папки.

Пример файла ввода list.txt выглядит следующим образом:

/In/Folder_1/SomeFoldername1/somefilename_x.mp3
/In/Folder_2/SomeFoldername2/somefilename_y.mp3
/In/Folder_3/SomeFoldername3/somefilename_z.mp3

Выходной файл (move.sh) должен выглядеть следующим образом после создания:

mv "/In/Folder_1/SomeFoldername1/somefilename_x.mp3"  /gain/Folder_1/
mv "/In/Folder_2/SomeFoldername2/somefilename_y.mp3"  /gain/Folder_2/
mv "/In/Folder_3/SomeFoldername3/somefilename_z.mp3"  /gain/Folder_3/

Структура папок должна быть сохранена, более или менее.

после выполнения созданного bash-скрипта (move.sh) результат должен выглядеть следующим образом:

/gain/Folder_1/somefilename_x.mp3
/gain/Folder_2/somefilename_y.mp3
/gain/Folder_3/somefilename_z.mp3

Что я сделал до сих пор.

1. создать список файлов с абсолютным путем

find /In/ -iname "*.mp3" -type f > /home/maars/mp3/list.txt

2. создать скрипт move.sh

cp -a /home/maars/mp3/list.txt /home/maars/mp3/move.sh 
# read the list and split the absolute path into fields
while IFS= read -r line;do
fields=($(printf "%s" "$line"|cut -d'/' --output-delimiter=' ' -f1-))
done < /home/maars/mp3/move.sh
# add the target path based on variables at the end of the line
sed -i -E "s|\.mp3|\.mp3"\"" /gain/"${fields[1]}"/|g" /home/maars/mp3/move.sh
sed -i "s|/In/|mv "\""/In/|g" /home/maars/mp3/move.sh

Сценарий просто использует значение ${fields[1]}, то есть Folder_1, и помещает его во все строки в конце. Вместо Папки_2 и Папки_3. Текущий результат выглядит как

mv "/In/Folder_1/SomeFoldername1/somefilename_x.mp3"  /gain/Folder_1/
mv "/In/Folder_2/SomeFoldername2/somefilename_y.mp3"  /gain/Folder_1/
mv "/In/Folder_3/SomeFoldername3/somefilename_z.mp3"  /gain/Folder_1/

rsync - не вариант, так как мне нужен полный контроль над перемещаемыми файлами.

Что я могу сделать лучше, чтобы решить эту проблему?

РЕДАКТИРОВАТЬ: @Socowi очень помог мне, указав мне в правильном направлении. После того, как я глубоко погрузился в мир регулярных выражений, я смог решить свои проблемы. Большое спасибо

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Сценарий просто использует значение $ {fields [1]}, то есть Folder_1, и помещает его во все строки в конце. Вместо Папки_2 и Папки_3.

Вы перебираете все строки и обновляете fields для каждой строки. После того, как вы закончили цикл, fields сохраняет свое значение (из последней строки). Вам нужно было бы переместить команды sed в ваш цикл и убедиться, что только текущая строка заменена на sed. Тем не менее, есть лучший способ - см. Ниже.

Что я могу сделать лучше

Есть много вещей, которые вы можете улучшить, например,

  • Создание массива fields с mapfile -d/ fields вместо printf + cut + ($()). Таким образом, у вас также не будет проблем с пробелами в путях.
  • Используйте sed только один раз вместо создания массива fields и использования нескольких команд sed. Вы можете заменить шаг 2 следующим небольшим скриптом:
cp -a /home/maars/mp3/list.txt /home/maars/mp3/move.sh 
sed -i -E 's|^/[^/]*/([^/]*).*$|mv "&" "/gain/\1"|' /home/maars/mp3/move.sh

Однако лучшей оптимизацией было бы отказаться от этого трехэтапного подхода и использовать только один скрипт для поиска и перемещения файлов:

find /In/ -iname "*.mp3" -type f -exec rename -n 's|^/.*?/(.*?)/.*/(.*)$|/gain/$1/$2|' {} +

Опция -n будет печатать то, что будет переименовано, фактически ничего не переименовывая. Удалите -n, когда вы довольны результатом. Вот вывод:

rename(/In/Folder_1/SomeFoldername1/somefilename_x.mp3, /gain/Folder_1/somefilename_x.mp3)
rename(/In/Folder_2/SomeFoldername2/somefilename_y.mp3, /gain/Folder_2/somefilename_y.mp3)
rename(/In/Folder_3/SomeFoldername3/somefilename_z.mp3, /gain/Folder_3/somefilename_z.mp3)
0 голосов
/ 01 ноября 2018

Это не встроено в bash, но команда mmv хороша для такого типа mv, где вам нужно использовать подстановочные знаки в путях. Должно работать что-то вроде следующего:

mmv "in/*/*/*" "#1/#3"

Обратите внимание, что это не создаст каталоги для вас - но в вашем примере выше, похоже, они уже существуют?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...