Выравнивание структуры папок

Выравнивание структуры папок

У меня такая структура папок:

├── foo1
│   ├── bar1.txt
│   └── bar2.txt
├── foo2
│   ├── bar3.txt
│   └── bar4 with a space.txt
└── foo3
    └── qux1
        ├── bar5.txt
        └── bar6.txt

которые я хотел бы свести к следующему, с подчеркиванием между каждым уровнем папок:

├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt

Я поискал и не нашел ни одного работающего решения, в основном потому, что, как мне кажется, у моей проблемы есть две особенности: внутри корневой папки может быть несколько уровней папок, а также потому, что некоторые файлы могут содержать пробелы.

Есть идеи, как это сделать в bash? Спасибо!

Редактировать: Бегущий Глин Джекман предложил ответ Я получаю это:

введите описание изображения здесь

Для папки первого уровня есть два подчеркивания. Есть идеи, как этого избежать или просто переименовать так, чтобы было только одно подчеркивание? Спасибо.

решение1

find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

удалите echo, если вы удовлетворены тем, что это работает. Не беспокойтесь, что команды, отображаемые с помощью echo, не показывают кавычек, скрипт будет правильно обрабатывать файлы с пробелами.

Если вы хотите удалить пустые подкаталоги:

find */ -depth -type d -exec echo rmdir '{}' \; 

решение2

Используя переименование perl:

find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;

ВЫХОД

$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt

ПРИМЕЧАНИЕ

  • Я используюнегативный взгляд позади (?<!\.)не трогать первый./
  • Я сохраняю пустые директории, не стесняйтесь:

    find . -depth -type d -exec rm {} \;

предупреждениеСуществуют и другие инструменты с таким же названием, которые могут или не могут сделать то же самое, поэтому будьте осторожны.

Если вы выполните следующую команду ( GNU)

$ file "$(readlink -f "$(type -p rename)")"

и у вас есть такой результат

.../rename: Perl script, ASCII text executable

и не содержащие:

ELF

тогда это, кажется, правильный инструмент =)

Если нет, сделать его значением по умолчанию (обычно это уже так) Debianи производным, например Ubuntu:

$ sudo update-alternatives --set rename /path/to/rename

(замените /path/to/renameна путь вашей perl's renameкоманды.


Если у вас нет этой команды, найдите ее в менеджере пакетов, чтобы установить, илисделать это вручную


И последнее, но не менее важное: этот инструмент изначально был написан Ларри Уоллом, отцом Perl.

решение3

сpax...

pax -Xrwls '|/|_|g' */ "$PWD"

Это создаст жесткую ссылку в текущем каталоге на все файлы в его дочерних каталогах с _заменой на /. Затем вы можете проверить результаты и удалить все дочерние каталоги с помощью...

rm -rf */

...как только вы убедитесь, что результаты вас устраивают.

решение4

Вы можете попробовать выполнить команду ниже.

$ find -type f -exec bash -c 'mv $0 $(echo $0|sed "s/\//_/2")' {} \;

Приведенная выше команда переместит файлы, а каталог останется, и его можно будет удалить позже.

$ ls
foo1_bar1.txt  foo1_bar2.txt  foo2_bar3.txt  foo2_bar4.txt  foo3_bar5.txt  foo3_bar6.txt

Связанный контент