Bash изменяет абсолютный путь в файле построчно для создания скрипта

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

Пример файла Input 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, и помещает его во все строки в конце. Вместо Folder_2 и Folder_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 мне очень помог, указав в правильном направлении. После того, как я глубоко погрузился в мир регулярных выражений, я смог решить свои проблемы. Большое тебе спасибо

Вы написали done < /home/maars/mp3/move.sh. Вы не имели в виду done < /home/maars/mp3/list.txt?

Socowi 01.11.2018 12:44
done < /home/maars/mp3/move.sh - это просто копия done < /home/maars/mp3/list.txt, как определено в строке 1. Я сохраняю done < /home/maars/mp3/list.txt для других занятий.
zumbi 01.11.2018 12:50

Ах я вижу. Другой вопрос; вы хотите переместить только файлы mp3 или целые каталоги? Если вы хотите переместить только файлы mp3: существуют ли уже целевые каталоги или их нужно создать?

Socowi 01.11.2018 13:38

только mp3. Целевые каталоги /gain/Folder_x/ уже существуют.

zumbi 01.11.2018 13:41

Но каталога /gain/Folder_1/SomeFoldername1 не существует. Ok.

Socowi 01.11.2018 13:55

В моем сценарии этой папки в настоящее время не существует, это правильно. Но в моем случае это не совсем необходимо. Если он будет создан, это нормально, но не важно.

zumbi 01.11.2018 13:59

Поскольку вы хотите получить /gain/Folder_1/SomeFoldername1/somefilename_x.mp3 в качестве конечного результата, вам нужно сначала создать /gain/Folder_1/SomeFoldername1. mv не может создавать каталоги.

Socowi 01.11.2018 14:04

это ясно. для пояснения я скорректировал окончательный вид на: /gain/Folder_1/somefilename_x.mp3/gain/Folder_2/somefilename_y.mp3/gain/Folder_3//somefilename_z.mp3

zumbi 01.11.2018 14:07
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
1 167
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

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

Ответ принят как подходящий

The script just use the value of ${fields[1]}, which is Folder_1 and put this in all lines at the end. Instead of Folder_2 and Folder_3.

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

What could I do better

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

  • Создание массива 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)

Я попытался применить sed -iE 's|^/[^/]*/([^/]*).*$|mv "&" "/gain/\1"|' /home/maars/mp3/move.sh, но получил сообщение об ошибке: sed: -e expression #1, char 40: invalid reference \1 on s 'command's RHS'

zumbi 01.11.2018 14:30

@zumbi Похоже, sed не терпит сокращенной формы -iE. Попробуйте еще раз с -i -E. См. Редактировать.

Socowi 01.11.2018 14:34

Он работал с -i -E. Мне нужно поиграть с find /In/ -iname "*.mp3" -type f -exec rename -n 's|^/.*?/(.*?)/.*/(.*)$|/gain/$1/$2|' {} +, чтобы понять это. потому что это еще не дает мне никаких результатов.

zumbi 01.11.2018 15:35

Возможно, у вас другой rename, чем я имел в виду. В Ubuntu rename - это символическая ссылка на /usr/bin/file-rename. Программа написана Ларри Уоллом (см. man rename | grep -A1 AUTHOR), а rename --version печатает /usr/bin/rename using File::Rename version 0.20. В других системах та же самая команда может иметь другое имя, например prename. Для получения дополнительной информации см. здесь и здесь.

Socowi 01.11.2018 19:04

Сначала мне нужно было установить rename.

zumbi 02.11.2018 09:36

Другие вопросы по теме