Удалить пустые подпапки, сохранить родительскую папку

15

Когда я использую

find /home/user/parentdir -type d -empty -delete

он рекурсивно ищет пустые подпапки внутри /home/user/parentdirи удаляет их. Но если /home/user/parentdirон также пуст, он также удаляет parentdirпапку, что для меня нежелательно.

Я хочу сохранить это parentdirв rsyncнекоторых файлах для резервного копирования или в облаке. После обработки мне нужно удалить пустые папки, но кажется, что непроизводительно воссоздавать parentdirкаждый раз.

Любые предложения, чтобы сохранить parentdir? Я думал о создании .nocopyфайла внутри него и исключить его из rsync, но выглядит излишним. Есть ли более элегантный способ?

тротил
источник
Если вы добавите косую черту / в конец / parentdir (т.е. / parentdir /), это будет иметь значение?
Грэм
6
-mindepth 1?
Стальная отвертка
@Graham / parentdir / также удаляет parentdir, поэтому без разницы.
TNT
Ах, я вижу, что пропустил * в конце, который @Amourk упоминает в своем ответе.
Грэм

Ответы:

25

Просто делай find /home/user/parentdir -mindepth 1 -type d -empty -delete.

Посмотрите:

$ mkdir -p test1/test2
$ find test1 -type d
test1
test1/test2
$ find test1 -mindepth 1  -type d
test1/test2

find /home/user/parentdir/* В ответе AmourK в Нежелательно , когда есть много файлов , и это усложненное.

СНХ
источник
15

Добавляя /*в конец parentdir, вы выполняете действие со всеми подкаталогами parentdir, а не над parentdirсамим собой. И поэтому точно так же /home/user/не удаляется в старой команде, parentdirне будет удаляться в команде ниже. *называется оператором glob и соответствует любой строке символов.

find /home/user/parentdir/* -type d -empty -delete

AmourK
источник
7
С этим подходом следует помнить одну вещь: если имеется большое количество файлов /home/user/parentdir/, размер расширенного глобуса может превышать ARG_MAX, что приводит к слишком длинной ошибке в списке аргументов . Вы можете уменьшить вероятность этого, изменив глобус */так, чтобы он совпадал только с каталогами.
Стальная отвертка
12
Также помните, что это не найдет детей, начинающихся с точки. И однажды вы поймете это, и если вы также найдете «. *», Вы окажетесь в огромном мире боли (потому что «. *» Соответствует «..»). Спроси меня, откуда я знаю.
Гленн Виллен
1
@GlennWillen, почему я думаю, что мы должны сидеть в баре с напитками перед нами, прежде чем я попрошу тебя рассказать эту историю?
Монти Хардер
@MontyHarder К счастью, все было не так плохо, как могло бы быть. Это была моя первая система Unix, которая была машиной Solaris, принадлежавшей моей школе. Слава богу, я не управлял «рм», а скорее «чоун». Я использовал root, чтобы попытаться исправить владение всем в моем домашнем каталоге. Вместо этого я дал себе право собственности на КАЖДЫЙ домашний каталог (и все их содержимое), а затем должен был вернуть их обратно.
Гленн Виллен
У меня был сотрудник, обучающий нового сотрудника тому, как установить часть программного обеспечения. Это включало в себя /tmpсоздание, создание подкаталога, распаковку сжатого архива, запуск установщика и очистку. Мысль новичка rm -rf /tmp/foo-installбыла правильным способом сделать это, и, как опытная рука сказала «Неееееееет» в своем лучшем впечатлении Дарта-Вейдера в конце Эпизода-III, новичок выяснил, как близко / и клавиши Enter были друг для друга. Мы должны были загрузиться с диска восстановления программного обеспечения резервного копирования и перезагрузить весь сервер с ленты.
Монти Хардер
0

если у вас установлен php-cli,

printf %s $(pwd) | php -r 'function f(string $dir){var_dump($dir);$dir.=DIRECTORY_SEPARATOR;foreach(glob("$dir*",GLOB_ONLYDIR) as $d){f($d);}global $original;if(substr($dir,0,-strlen(DIRECTORY_SEPARATOR))!==$original && empty(glob("$dir*"))){rmdir($dir);}}f(($original=stream_get_contents(STDIN)));'
hanshenrik
источник
Вы хотели foreach (RecursiveIteratorIterator(RecursiveDirectoryIterator($dir)) as $p) if (empty($skipped)) $skipped = TRUE; elseif ($p->isDir()) @rmdir($p->getPathname());или что-то подобное. $skippedзаботится о пропуске первого, @rmdirпытается удалить dir и молча (это @) завершается неудачей, если не пустой.
chx
0

Когда вам нужен только один уровень (оставление родительской папки, но удаление пустых дочерних папок), использовать простой прием rmdir.

rmdir parent/*

Удаляет все пустые подпапки, но печатает только ошибку для файлов и непустых папок.

Это не работает рекурсивно, но, зная структуру вашей папки, это может быть самый быстрый способ сделать что-то вроде

rmdir parent/*/*/* # deletes parent/a/b/c when empty
rmdir parent/*/* # deletes parent/a/b when it is now empty
rmdir parent/* # deletes parent/a when it is now empty

Преимущество: Легко запомнить, быстро печатать, мало возможностей для выбора неправильного параметра.
Недостаток: менее гибкий, возможно много сообщений об ошибках в вашем терминале.

алло
источник