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

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

У меня есть ситуация, когда у меня есть 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.

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

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


person lawreaf    schedule 29.09.2014    source источник
comment
типовой вопрос для операций с файлами, особенно для графа DIR .... Продолжайте публиковать и удачи!   -  person shellter    schedule 29.09.2014


Ответы (2)


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

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

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

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

person gandaliter    schedule 29.09.2014
comment
По какой-то причине мне пришлось дать полное разрешение Другим (создавать и удалять файлы), иначе я получил сообщение «Невозможно переместить файл ПРИМЕР, разрешение отклонено». - даже когда я запускал как SUDO. Я не уверен, почему это так, но как только я дал новые разрешения, это решило мою проблему. Огромное спасибо. - person lawreaf; 29.09.2014
comment
Если вы поместите sudo перед этой командой, то она будет применяться только к команде find, а не к команде xargs, которая фактически выполняет перемещение. Рад, что у вас все же заработало. - person gandaliter; 29.09.2014

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

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/
person Reinstate Monica Please    schedule 29.09.2014