Як видалити каталоги на основі результату "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! :)
Drav Sloan

10
@Marco Опція видалення, здається, не працює в каталогах.
Арно

@SuperChafouin Тут чудово працює тут файли та каталоги. Справа в тому, що він видаляє лише каталоги emtpy, і коли ви вказуєте, -name ".svn"він відповідає лише самому .svnкаталогу, а не файлам, що знаходяться в .svnкаталозі.
Марко

1
@SuperChafouin, але не буде працювати для шляхів з пробілами в них (отже, використовуючи -execз цитатами "{}").
Драв Слоун

Відповіді:


194

Find може виконувати аргументи з -execможливістю для кожного знайденого відповідності. Це рекомендований механізм, оскільки ви можете правильно обробляти шляхи з пробілами / новинками та іншими символами. Ви повинні будете видалити вміст каталогу , перш ніж можна видалити сам каталог, так що використовуйте -rз rmкомандою для досягнення цієї мети.

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

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

Ви також можете сказати знайти, щоб просто знайти каталоги з назвою .svn, додавши -type dчек:

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

Попередження Використовуйте rm -rз обережністю, вона видаляє папку та весь її вміст.

Якщо ви хочете видалити просто порожні каталоги, а також каталоги, що містять лише порожні каталоги, знайдіть, що можна зробити це за допомогою -deleteі -empty:

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

21
Я бачив пораду завжди працювати -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
Яка різниця між + і крапкою з комою? Чому ми не використовуємо фігурні брекети?
Shicheng Guo

1
@ShichengGuo З крапкою з комою знайдеться одна команда rm на кожен каталог, при цьому команда + одна команда rm обробить усі знайдені каталоги (або, принаймні, дуже велика їх кількість.) Я не отримую вашого другого питання, кучеряве тут використовуються брекети.
jlliagre

Я думаю, що @ShichengGuo означає, чому нам тут не потрібно цитувати фігурні дужки (@jlliagre писав, що нам ніколи не потрібно цитувати їх). Зараз я не можу знайти посилання, але я розумію, що це тому, що Find автоматично вийде із шляхів, замінених на {}.
Квінн Комендант

Відповідь і питання не зовсім правильні щодо того, що робить +. Якщо знайдено багато файлів, то ';' призведе до помилки "командного рядка занадто довго". + розбиває файли, знайдені в партіях, що не перевищують максимальну довжину командного рядка, і виконує команду для кожної партії.
gaoithe

1
@gaoithe Я відмовив вас від редагування, який замінив правильне твердження на неправильне. Використання + ж знизити навантаження на процесор, використовуючи ; НЕ призводить до команди занадто довго помилка.
jlliagre

27

Припустимо, що ви використовуєте gnu find , ви можете скористатися -deleteопцією:

find . -name test -delete

що легше запам’ятати.


Спробуйте розширити свою публікацію, пояснивши команду (або документацію для резервного копіювання рішення). Часто відповіді на один (або два) рядки не є найбільш яскравими.
HalosGhost

93
Це не працює в непорожніх каталогах.
белакква

2
також працює на Mac OS X
нічия

Це не працює для непорожньої папки, але це простіше і безпечніше рішення
RousseauAlexandre

Порядок варіантів є дуже важливим, знайдіть, виконайте їх так, - виберіть останній
Хосе Ігнасіо Сентено

13

На моєму комп’ютері, коли я використовую:

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

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

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

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

Мої каталоги не порожні, тому опція -delete не працюватиме для мене. Я знайшов причину такої поведінки тут :

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

Я використовував це замість цього, щоб обійти:

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

Майте на увазі, що пошук все ще спробує повторно вписатись у каталоги з назвою 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.
Mapio

1
Додайте, -pruneщоб уникнути помилки "Немає такого файлу чи каталогу".
Жульєн Карсік

12

Швидший спосіб зробити це:

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

Якщо у вас є ".svn" всередині іншого ".svn".


Це не дуже корисно, якщо ви хочете знайти каталоги, які слід видалити за допомогою підкаталогів.
Алексіс Вілке

5

Конкретне рішення для Баша:

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.