Сглаживание структуры папок

8

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

├── 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? Спасибо!

Редактировать : Запуск Глин Джекман предложил ответ, я получаю это:

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

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

nunos
источник

Ответы:

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

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

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

find */ -depth -type d -exec echo rmdir '{}' \; 
Гленн Джекман
источник
Привет. Это потрясающе! Спасибо. Это сделало трюк почти полностью. У меня просто небольшая проблема, которую я получаю foo1__qux1_bar5.txt, два подчеркивания на первом уровне папок. Пробовал возиться с вашей линией bash, но ничего не получалось. Может быть, мне нужно что-то добавить?
nunos
@nunos, я не могу воспроизвести это поведение
Гленн Джекман
В самом деле? Weird. Я только что обновил свой ответ с дополнительной информацией. Можете ли вы взглянуть? Спасибо.
nunos
1
да. ОК, измените "${file//\//_}"на "${file//+(/)/_, и если это сценарий,shopt -s extglob
Гленн Джекман
У меня была проблема с двумя подчеркиваниями. К сожалению, изменение команды, как вы предложили, не работает для меня. Однако я нашел этот ответ на AskDifferent: apple.stackexchange.com/a/254224/122152 Согласно ответу, macOS может использовать BSD find. Обходной путь можно использовать findutils. Он может быть установлен с помощью доморощенного с, brew install findutilsа затем с помощью gfindвместо find. Это сработало для меня.
января
5

Использование переименования 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

НОТА

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

Если вы запустите следующую команду ( 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.

Жиль Квено
источник
... -type d -exec rmdir ...?
JJoao
У меня, кажется, нет переименования, доступного .. Как именно я могу получить его, и обычно ли это доступно в системе UNIX? Спасибо.
nunos
@nunos Это скрипт на Perl. Он доступен под именем perl-renameв Arch Linux и prenameв системах на основе Debian.
Муру
Добавлены renameобъяснения
Жиль Квено
1

с pax...

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

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

rm -rf */

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

mikeserv
источник
0

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

$ 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
Каннан Мохан
источник