Видаліть усі папки всередині папки, крім однієї із конкретним іменем


18

Мені потрібно видалити всі папки всередині папки за допомогою щоденного сценарію. Папку на цей день потрібно залишити.

У папці 'myfolder' є 3 підпапки: 'test1', 'test2' та 'test3' Мені потрібно видалити всі, крім 'test2'.

Я намагаюся відповідати точній назві тут:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

АБО

find /home/myfolder -type d ! -name 'test2' -delete

Ця команда завжди намагається також видалити головну папку "myfolder"! Чи є спосіб цього уникнути?


6
У Unix та Linux ми називаємо ці "каталоги", а не "папки".
tchrist

1
Залежно від вашої оболонки, вам може знадобитися цитувати цього !оператора: \!або '!'.
Toby Speight

Відповіді:


32

Це видалить усі папки всередині, ./myfolderкрім цього, ./myfolder/test2і весь його вміст буде збережено:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

Як це працює

  • find запускає команду пошуку.
  • ./myfolderповідомляє пошук починати з каталогу ./myfolderта його вмісту.

  • -mindepth 1 не відповідати ./myfolderсобі, лише файли та каталоги під ним.

  • ! -regex '^./myfolder/test2\(/.*\)?' каже знайти, щоб виключити ( !) будь-який файл або каталог, що відповідає регулярному виразу ^./myfolder/test2\(/.*\)?. ^відповідає початку назви шляху. Вираз (/.*\)?відповідає або (а) косою рисою, за якою слідує що-небудь, або (b) взагалі нічого.

  • -delete повідомляє знайти, щоб видалити відповідні (тобто невиключені) файли.

Приклад

Розглянемо схожу структуру каталогу;

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

Ми можемо запустити команду find (без -delete), щоб побачити, що вона відповідає:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

Ми можемо переконатися, що це спрацювало, переглянувши файли, що залишилися:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

1
Альтернативно -pruneзалишити test2/*/підкаталоги в спокої: повернутися до rm -rта додати -maxdepth 1.
Toby Speight

@Isaac ОК. Зроблено. (Також +1 за відмінну відповідь.)
John1024

Відмінна робота !, але вибачте: це видалить усі файли всередині ./myfolder. Вам потрібний відсутній (IMvhO) лише-type d для каталогів .
NotAnUnixNazi

Гаразд, це має працювати так, як вам хочеться:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
NotAnUnixNazi

10

Використання bash :

shopt -s extglob
rm -r myfolder/!(test2)/

Приклад:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file

5

тл; д-р

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

Видаліть ехо, якщо задоволений списком файлів.


Використання -mindepth 1гарантує, що верхній каталог не вибрано.

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Але -not -name test2застереження не уникне підкаталів всередині test2:

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Для цього вам потрібно щось на зразок чорносливу:

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Але не використовуйте delete, як це випливає, depthі це почне стирання з найдовшого шляху:

$ find ./myfolder -depth -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

Будь-яке використання rm -rf(видаліть, echoякщо ви хочете фактично стерти):

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

Або також використовуйте, maxdepthякщо все, що вам потрібно, - це видалити каталоги (і все, що знаходиться всередині) (видаліть, echoщоб насправді видалити):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

A -deleteвсе одно не вдасться, якщо каталог не порожній:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty

2

Якщо ви використовуєте zsh, ви можете:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

Тестували за допомогою команди нижче, і це працювало чудово

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;

Ви зіткнулися з тією ж проблемою, що і з ОП; Лістинг / home / папка в командному рядку (без критичного -mindepth 1) робить те, що верхній каталог відповідає всім критеріям (це каталог, і він не називається "test2"), і тому його видаляють.
Jeff Schaller
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.