Удаление уровня в файловой структуре с помощью Bash при сохранении файлов

Заранее спасибо за ваше время и помощь.

У меня есть ситуация, когда у меня есть DIR, который содержит несколько десятков вложенных DIR, где все вложенные DIR содержат только один файл (по какой-то ошибочной причине). Я пытаюсь переместить все файлы вверх на два уровня в дереве DIR, сохраняя при этом структуру файла другими способами. Вот пример того, что я имею в виду:

|--- DIR.Main
|--- |---DIR.Sub-A
|--- |--- |--- File.Sub-A
|--- |---DIR.Sub-B
|--- |--- |--- File.Sub-B
|--- |---DIR.Sub-C
|--- |--- |--- File.Sub-C
|-->Continue for approx. 50 DIR.Subs

Мне не нужен уровень DIR.Sub в файловой структуре, и я бы хотел, чтобы он выглядел так:

|--- DIR.Main
|--- |---File.Sub-A
|--- |---File.Sub-B
|--- |---File.Sub-C

Вот в чем проблема сложности: имена файлов расположены не так аккуратно и логически, как в предыдущем примере, а случайным образом названы так:

|--- DIR.Main
|--- |---DIR.Sasjaljesea
|--- |--- |--- File.Sasjalsaejesea.mpg
|--- |---DIR.qwerqwerewqwer
|--- |--- |--- File.qwerqweresezswqwer.mpg
|--- |---DIR.xcbxcvxcvbxcvb
|--- |--- |--- File.xcsfasdbxcvxcvbxcvb.mpg
|-->ETC

Однако экономия заключается в том, что, как и в приведенном выше примере, все файлы имеют один и тот же тип файла (в данном случае mpg).

Я прочитал документацию по mv и cp в Bash и не смог придумать способ сделать это за один проход без ввода всех имен файлов вручную. Я также изучил варианты с Xrandr и аналогичными командами. Самое близкое, что я смог прийти к решению, это:

find /path/to/search -type f -iname "*.mp3" -exec mv {} path/to/music \;

Взято из этого ответа: перемещение нескольких файлов в подкаталогах (и / или разбиение строк с помощью многоканального разделителя) [bash]

Где я, очевидно, исправил -iname в.mpg и DIR, чтобы соответствовать моей ситуации.

Когда я сделал это, он нашел все файлы и переместил их в нужную мне папку, но объединил все файлы в один нечитаемый файл.mpg вместо того, чтобы рекурсивно копировать каждый отдельный файл и поддерживать структуру файла так, как я хотел. Я исследовал использование cp рекурсивно в приведенной выше команде вместо mv, но это, похоже, ничего не дало, даже когда я выполнял как SUDO. У cp возникает дополнительная проблема: я не хочу дублировать файлы, просто удалите промежуточную папку, в которой они содержатся.

Вы, наверное, поняли, что я стараюсь избегать простого использования графического интерфейса в Linux и идти по пути Bash по той очевидной причине, что для этого потребуется несколько часов в диспетчере окон, тогда как я уверен, что есть способ сделать это в Bash в считанные секунды. Это задача, которая обычно занимает несколько секунд в диспетчере файлов Linux, если один из них имеет дело с менее чем дюжиной папок и файлов для перемещения, но текущая ситуация такова, что существуют десятки ненужных DIR, заключающих в себе только одну файл. Следовательно, мне нужен хороший чистый раствор Bash.

Еще раз спасибо за вашу помощь. Это проблема, которая меня раздражала уже несколько недель.

Я приветствую любые вопросы.

2 ответа

Решение

xargs используется с mv может решить это. Вы должны начать с текущего рабочего каталога DIR.Mainи с другим каталогом, чтобы переместить все в. Он должен отличаться, потому что в противном случае вы получите (пустые) исходные каталоги, чередующиеся с вашими новыми файлами и каталогами. Мы могли бы обойти это, но я не думаю, что это нужно.

find -maxdepth 2 -mindepth 2 | xargs -I '{}' mv '{}' <PATH_TO_NEW_LOCATION>/

find Результатом является список всех файлов и каталогов, которые находятся ровно на один уровень дальше в дереве каталогов, чем текущий каталог. xargs call затем перемещает все эти результаты в указанное место.

Я проверил его, но вы можете также проверить его, прежде чем использовать его в своих живых данных или, по крайней мере, взять копию.

Это должно быть так же просто, как

shopt -s dotglob; mv -iv DIR.Main/*/* DIR.Main/

Если вы нажмете ARG_MAX поместите это в петлю

shopt -s dotglob; for f in DIR.Main/*/*; do mv -iv "$f" DIR.Main/
Другие вопросы по тегам