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


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

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

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

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

Ответы:


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 */

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


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.