Как удалить каталоги на основе вывода `find`?


148

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

find . -name ".svn"

Это дает мне следующие результаты:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

Как я могу обработать все эти строки rm -fr, чтобы удалить каталоги и их содержимое?


3
У GNU find есть -deleteопция.
— Марко

5
Или вы можете добавить -exec rm -r "{}" \;в конец находки - будьте осторожны при использовании rm -r! :)
— Драв Слоан

10
@Marco Опция удаления, похоже, не работает с каталогами.
— Арно

@SuperChafouin Отлично работает здесь с файлами и каталогами. Дело в том, что он удаляет только каталоги emtpy, и при его указании -name ".svn"он соответствует только .svnсамому каталогу, а не файлам, расположенным в .svnкаталоге.
— Марко

1
@SuperChafouin, но не будет работать для путей с пробелами в них (следовательно, используется -execс кавычками "{}").
— Драв Слоан

Ответы:


195

Find может выполнять аргументы с -execопцией для каждого найденного совпадения. Это рекомендуемый механизм, потому что вы можете правильно обрабатывать пути с пробелами / символами новой строки и другими символами. Вам придется удалить содержимое каталога, прежде чем вы сможете удалить сам каталог, поэтому используйте для -rэтого rmкоманду.

Для вашего примера вы можете выдать:

find . -name ".svn" -exec rm -r "{}" \;

Вы также можете указать find только найти каталоги с именем .svn, добавив -type dпроверку:

find . -name ".svn" -type d -exec rm -r "{}" \;

Предупреждение Используйте rm -rс осторожностью, чтобы удалить папку и все ее содержимое.

Если вы хотите удалить только пустые каталоги, а также каталоги, которые содержат только пустые каталоги, find может сделать это самостоятельно с помощью -deleteи -empty:

find . -name ".svn" -type d -empty -delete

22
Я видел советы , чтобы всегда работать -type после -name того, как в командах найти, так как звонки на statполучить тип дороги. Я сам попробовал это на довольно большой пачке файлов, и это похоже на правду: работа find . -name 'foo' -type dзаняла 19 секунд, а find . -type d -name 'foo'заняла 32 секунды. Так что на 50% больше времени, чтобы бежать -typeпервым.
— раскрутка

6
Я использую эту команду в течение многих лет, но на Mac теперь я получаю сообщения о том, что эти каталоги не существуют. Даже при том, что это удаляет их. Я никогда не видел сообщений раньше.
— Чови

1
То же, что и @chovy. Есть ли способ избавиться от этих сообщений?
— Clément

2
@chovy @ clément Это потому, что findхочет видеть в этой папке другие совпадения, одновременно удаляя папку. ~ Я пока не знаю, как это исправить. ~ Грязное исправление:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
— Чарли

5
@chovy @ Clément Я думаю, что -depthаргумент исправляет это:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
— gimboland

67

Вот портативный еще быстрее, чем принятый способ ответа.

Использование +вместо точки с запятой в качестве разделителя findкоманд оптимизирует использование ЦП. Это может быть важно, если у вас много .svnподкаталогов:

find . -name .svn -type d -exec rm -rf {} +

Следует также отметить , что вы никогда не 1 необходимости цитировать фигурные скобки здесь.

1 Если вы не используете fishоболочку.


5
Какая разница между + и точкой с запятой? Почему мы не используем фигурные скобки?
— Шичен Го

1
@ShichengGuo С точкой с запятой, будет найдена одна команда rm для каждого найденного каталога, а с помощью + команда + rm обработает все найденные каталоги (или, по крайней мере, очень большое их количество). Ваш второй вопрос не получится, вьющийся здесь используются скобки.
— jlliagre

Я думаю, что @ShichengGuo означает, почему нам не нужно указывать здесь фигурные скобки (@jlliagre написал, что нам никогда не нужно их заключать в кавычки). Я не могу найти ссылку сейчас, но я понимаю, что это потому, что find автоматически экранирует пути, замененные на {}.
— Куинн Комендант

Ответ и вопрос не совсем верны в отношении того, что делает +. Если найдено много файлов, то ';' выдаст ошибку «слишком длинная командная строка». + разбивает файлы, найденные в пакетах, которые меньше максимально допустимой длины командной строки, и запускает команду для каждого пакета.
— gaoithe

1
@gaoithe Я сделал откат, который вы редактировали, который заменил правильное утверждение неправильным. Использование + же снизить нагрузку на процессор, используя ; не приводит к команде слишком долго ошибка.
— Jlliagre

27

Предположим, вы используете gnu find , вы можете использовать -deleteопцию:

find . -name test -delete

что легче запомнить.


Подумайте о расширении вашего поста объяснением команды (или документацией для резервного копирования вашего решения). Часто одна (или две) строковые ответы не являются наиболее яркими.
— HalosGhost

94
Это не работает на непустых каталогах.
— belacqua

2
также работает на Mac OS X
— отрисовка

Это не работает для непустой папки, но это более простое и безопасное решение
— RousseauAlexandre

Порядок опций очень важен, команда find выполнит их по порядку, так что, - удаление должно быть последним
— Jose Ignacio Centeno

13

На моем компьютере, когда я использую:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Каталоги удалены, но я получаю ошибку:

find: ‘./dirname’: No such file or directory

для каждого каталога.

Мои каталоги не пусты, поэтому опция -delete для меня не сработает. Я нашел причину такого поведения здесь :

  1. find берет (не обязательно) первую запись в каталоге ./. это будет, например, dir.1 /
  2. он сравнивает его с шаблоном «dir.?». это совпадает? да.
  3. find выполняет "rm -r dir.1".
  4. find пытается ввести dir.1 /, чтобы найти шаблон в каталоге. он ничего не знает о команде exec.
  5. он не находит dir.1 / больше. возвращает ENOENT (посмотрите на вывод strace)

Я использовал это вместо этого, чтобы обойти:

rm -r `find . -name dirname -type d`

Имейте в виду, что find по-прежнему будет пытаться перейти в каталоги с именем dirname, что на самом деле не является необходимым и займет некоторое дополнительное время. В зависимости от структуры вашего каталога, вы можете обойти это с помощью --depthопции поиска. Кроме того, если у вас есть структура каталогов, такая как dirname / foo / dirname, вы получите сообщение об ошибке «Нет такого файла или каталога» от rm. Чтобы подавить ошибки, вы можете перенаправить stderr в / dev / null или использовать -fфлаг (force) с rm.


2
Плохая идея: имя файла с пробелами вызовет всевозможные ужасные проблемы
— Clément

2
Для будущих читателей: find . -name "to-delete" -print0 | xargs -r0 -- rm -rэто отказоустойчивая версия, которая не падает на пробелах
— Чарли

3
См. Unix.stackexchange.com/a/115869/8257, который необходимо добавить -prune.
— Мапио

1
Добавьте, -pruneчтобы избежать ошибки «Нет такого файла или каталога».
— Жюльен Карсик

12

Более быстрый способ сделать это:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

Если у вас есть «.svn» внутри другого «.svn».


Это не очень полезно, если вы хотите найти каталоги для удаления с подкаталогами.
— Алексис Уилке

5

Bash конкретное решение:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion

3
Примечание: для расширения командной строки глобусов, которые соответствуют многим файлам, существует ограничение на количество файлов, которые вы можете сопоставить с этим механизмом. Превышение этого предела приведет кbash: /bin/rm: Argument list too long
— Драв Слоан

1
@DravSloan верен, но это ограничение в сотнях тысяч файлов. Об этом нужно помнить, но, вероятно, это не будет проблемой для большинства людей.
— evilsoup

4

Я обнаружил, что -deleteдействие хорошо работает с -pathтестом. Например, следующее должно работать на оригинальной проблеме плакатов:

find . -path '*/.svn*' -delete

Ты уверен? -deleteподразумевает -depth, и это, безусловно, удаляет непустые каталоги в моей системе.
— Магнус

Проверено, и это работает. Может быть, это была просто опечатка, которую я исправил.
— kenorb

Я также попробовал этот подход, и он работал - каталоги были удалены.
— Аллан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.