Удаление уровня в файловой структуре с помощью 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/