Як видалити всі підкаталоги з каталогу?


51

Це питання є своєрідною II фазою до першого питання, яке я розмістив тут

У мене є каталог, який містить купу підкаталогів, .zip файлів та інших випадкових файлів, які не містяться в підкаталозі.

Я хотів би скрипт командного рядка видалити всі підкаталоги з батьківського каталогу, але зберігати всі zip-файли та вільні файли, які не належать до жодного підкаталогу. Усі підкаталоги містять вміст, тому я вважаю, що мені потрібно змусити їх видалити команду -f.

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

Я розумію, що для видалення елементів з командного рядка потрібна особлива обережність, але я вже вжив усіх необхідних заходів безпеки для віддаленої резервної копії.

Відповіді:


61

У BASH ви можете скористатися косою косою рисою (я думаю, вона повинна працювати в будь-якій оболонці POSIX):

rm -R -- */

Зверніть увагу, --що розділяє параметри від аргументів і дозволяє видалити записи, починаючи з дефісу - інакше після розширення оболонкою ім'я запису буде інтерпретуватися як опція rm(те саме стосується багатьох інших утиліт командного рядка).

Додайте -fопцію, якщо ви не хочете, щоб під час видалення файлів, що не записуються, вам потрібно буде підтвердити підтвердження.

Зауважте, що за замовчуванням приховані каталоги (ті, з яких починається ім’я .) залишаться в спокої.

Важливий застереження: розширення */також буде містити символьні посилання, які врешті-решт вирішать файли типу каталогу . І залежно від rmреалізації rm -R -- thelink/буде або просто видалити symlink, або (в більшості з них) видалити вміст пов'язаного каталогу рекурсивно, але не сам каталог, ані символьне посилання.

Якщо використовувати zsh, кращим підходом було б використовувати глобальний класифікатор для вибору файлів лише каталогів типу:

rm -R -- *(/) # or *(D/) to include hidden ones

або:

rm -R -- *(-/)

для включення символьних посилань до каталогів (але, оскільки цього разу розширення не має трейлінг- /s, це видаляється лише символьне посилання з усіма rmреалізаціями).

З bash, AT & T ksh, yashабо zshви можете зробити:

set -- */
rm -R -- "${@%/}"

зняти зачіску /.


Гарний! Це прекрасно працює. Я не розумів, що це зробити так просто. Ви б не хотіли детальніше зупинитися на -r vs. -R і що ці команди виконують? Дуже дякую.
Евстер

-r, -R, --recursiveЄ синонімами означає «видалити каталоги і їх вміст рекурсивно».
петерф

ви можете пояснити, що - і * / робити?
амфібій

6
Ви також можете сказати rm -R ./*/- Це також уникає проблем із назви дефісів.
l0b0

1
Будьте обережні, щоб не змінити порядок * і /. rm -R - / * робить щось зовсім інше, що ви, можливо, не хочете, щоб сталося: |
ChrisOdney

13

На додаток до підстановочного способу, ви також можете використовувати find(принаймні GNU знайти) для цього:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 rm -R

Як і в інших findрядках, ви можете запустити першу частину ( find -mindepth 1 -maxdepth 1 -type d), щоб побачити список каталогів, які будуть видалені.

Більш безпечний варіант - зробити щось подібне:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 mv -i -t ../to-rm
# or
mv -i -t ../to-rm */
# or
mv -i */ ../to-rm

будь-який з яких перемістить усі речі ../to-rmзамість видалення. Ви можете переконатися, що він зробив те, що хотіли, ті, rm -Rfщо довідають у ваше дозвілля.


+1 для "CLI-смітник" to-rmі findякий прекрасно обробляє каталоги, починаючи з крапки (крім будь-яких інших громіздких втечі). :)
петерф

Дякую за пораду. Мені подобається ідея переїхати в окремий каталог перед видаленням. Я працюю через Terminal на Mac OS X, і я вважаю, що мені потрібно встановити якийсь пакет GNU, щоб використовувати команди -mindepth і -maxdepth, правда?
Евстер

@Evster не впевнений, чи підтримує Mac OS X підтримку. Я б здогадався, що фінк (це все ще існує?) Міг би встановити знахідку. Або ви можете їх опустити, а потім відфільтрувати створений список файлів за допомогою grep. Однозначно використовуйте опцію mv на цьому, istad з rm.
дероберт

4

Можливо, ви хочете створити сценарій для деяких із цих пропозицій, особливо rm -R -- */, і зберігати його у папці / usr / local / bin; або створити aliasу файлі ~ / .bashrc. Оскільки так легко ввести команду і порушити вашу систему - навіть одна літера та / або порядок букв можуть призвести до катастрофічних наслідків - це послужить дещо надійнішим рішенням, ніж необхідність вводити різні параметри та аргументи кожного разу, коли ви хочете виконати це завдання.

Крім того, ви можете включити в свій скрипт / команду параметр -i or --interactive=onceабо -I or --interactive=alwaysваріант, який буде служити ще одним інструментом для уникнення випадкових видалень.

Крім того, щось на кшталт запропонованого деробертом було б найкращим; просто скопіюйте / вставте скрипт у файл / редактор терміналів і відрегулюйте його під ваші конкретні потреби, і файли / каталоги будуть переміщені в єдиний каталог (вміст якого ви можете перевірити / перевірити), який ви можете просто видалити видаючи rm -rfкоманду.

Інший варіант - використовувати GUI-додаток, такий як ваш файловий менеджер, і просто вибрати всі застосовні файли / папки, які ви хочете видалити. Перевірте сторінки посібників вашого дистрибутива, якщо у вас немає дозволів.

Нарешті, якщо папки порожні - по суті прості назви файлів - ви можете скористатися rmdirкомандою для їх видалення. Це не працює для всього, що ви хочете видалити, але це стане в нагоді в ті часи, коли ви хочете зробити «прибирання будинку». ** Ви можете спробувати -p --ignore-fail-on-non-emptyваріант, який дозволить вам видалити певні підкаталоги, а також їх порожні "батьки" - каталоги, в яких вони проживають.


Це дійсно гарна ідея створення окремого сценарію, який я можу закликати до цієї команди. Чи можете ви пояснити, що саме роблять варіанти -i та -I? Дякую!
Evster

-I опція підкаже вам один раз після натискання клавіші "Enter", щоб підтвердити, що ви хочете видалити це (коли "вибрано" більше 3 файлів / папок); тоді як опція -i видасть підказку для кожного файлу, після чого ви можете просто підтвердити, натиснувши "y" та "Enter" - все, крім позитивного відповіді, призведе до того, що конкретний файл буде пропущений у процесі видалення.
ILMostro_7

1

Спочатку потрібно перелічити каталоги, а потім видалити їх, не перешкоджаючи нормальним файлам, ls -d * /, лише перелічує підкаталоги, а трубопровід з rm видаляє каталоги та вміст, зберігаючи вільні файли недоторканими.

Ця команда повинна виконати цю роботу,

ls -d  */ | xargs rm -rf

1
Над якою буде користь rm -rf -- */? printf '%s\0' */ | xargs -r0 rm -rf --допоможе (в оболонках, де printfвбудовано, а не ls), обійти список аргументів занадто великих помилок, але ls -d */ | xargs rm -rfне додасть нічого AFAICT, крім додаткових проблем.
Стефан Шазелас

1
@AnthonyGeoghegan, так, наприклад, якщо б був каталог з назвою " .."(пробіл ..), він видалив би вміст батьківського каталогу з деякими lsреалізаціями. І це не лише пробіли, це ще й інші порожні символи, новий рядок, одинарна цитата, подвійна цитата, зворотна косої риски та назви файлів, починаючи з -.
Стефан Шазелас

2
@Ankit, Ви можете почати з mywiki.wooledge.org/ParsingLs
Stéphane Chazelas

1
Коли ви повністю розумієте пропозицію @ StéphaneChazelas використовувати printfдля створення списку, де кожне ім’я закінчується нульовим символом, щоб воно могло бути оброблене за xargsдопомогою -0параметра, я б радив вам відредагувати свою відповідь, щоб оновити її з його варіацією. Я був би досить впевнений, що він буде радий вам використовувати його фрагмент коду, якщо ви його розумієте і дізнаєтесь, як він захищає від небажаної поведінки, викликаної певними іменами файлів, які потенційно можуть існувати.
Ентоні Г - справедливість для Моніки

1
Використання xargsмає одну перевагу перед прийнятою відповіддю (вона працює, коли в поточному каталозі дуже велика кількість файлів / каталогів), тому є можливість редагувати це у корисну відповідь. Особисто я вважаю, що відповіді на питання Stack Exchange є гарним досвідом навчання, особливо коли я отримую корисну зворотну інформацію від інших користувачів.
Ентоні Г - справедливість для Моніки

-1

rm -rf <directory name>. Це працює. Просто введення тексту rm <directory name>призводить до кількості додаткових запитань, у яких кожну з підкаталогів потрібно видалити вручну. Але rm -rfдопомагає одразу видалити весь каталог разом із його підкаталогами.


5
ОП попросила зберегти вміст поточного каталогу.
Стівен Раух
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.