Исключение определенных файлов и каталогов при удалении файлов

11

Мой каталог верхнего уровня data. dataвключает в себя несколько каталогов, и эти каталоги имеют подкаталоги. Мне нужно удалить все файлы и каталоги внутри, data/кроме нескольких файлов в некоторых каталогах.

Например, данные включают в себя каталоги 100и 101. Я просто хочу сохранить a.txtи b.txtфайлы в 100/и c.txtи d.txtфайлы 101/при удалении всех других файлов и каталогов в 100и 101.

Пример:

.
├── 100
   ├── a.txt
   ├── b.txt
   ├── c.txt
   └── d.txt
└── 101
    ├── a.txt
    ├── b.txt
    ├── c.txt
    └── d.txt

Я использую rm -rf !(a.txt|b.txt)команду, но не могу применить эту команду для каждого каталога автоматически.

темно-синий
источник

Ответы:

12

Как вы уже узнали, вы можете использовать extglobфункцию, которая включена с:

shopt -s extglob

Это позволяет исключить совпадения, чтобы вы могли делать такие вещи, как:

rm 100/!([ab].txt) 101/!([cd].txt)

Это хорошая идея, чтобы проверить это в echoпервую очередь. Этот пример будет соответствовать всему, 100/что не является a.txtили, b.txtи всему, 101/что не является c.txtили d.txt. Если к вам 100/применимы те же правила 102/, например:

10[02]/!([ab].txt) # or
{100,102}/!([ab].txt)
Десерт
источник
Я только что привел пример для 100 и 101 каталогов, но на самом деле количество подкаталогов составляет почти 20. Можно ли реализовать приведенный выше код для каждого каталога без записи каждого имени каталога в основной папке?
Deep Blue синий
@deepblue Пожалуйста, предоставьте точный пример для этого в своем вопросе ( правка ), особенно неясно, как rmзнать, какие файлы хранить в каких каталогах, если вы не хотите это указывать.
десерт
7

Вы могли бы использовать findдля этого. Вы можете отменить тесты findс помощью -notили !. Это исключит совпадения, а не их поиск.

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

На основании вашего примера вы можете сделать что-то подобное из dataкаталога.

find ! -path . ! -path ./100 ! -path ./101 ! -path "./100/[ab].txt" ! -path "./101/[cd].txt"

Добавьте ! -path ./path/to/dirдля любого пути, который вы хотите избежать. Вы можете использовать метасимволы как *, но убедитесь, что вы цитируете выражение, если вы делаете, например "./path*dir", чтобы предотвратить любые нежелательные расширения.

findявляется рекурсивным по умолчанию. Даже если мы не найдем ./100здесь, мы найдем все его содержимое, если они не соответствуют шаблону [ab].txt. Если вы не можете сопоставить все имена, которые хотите сохранить, добавьте еще один тест:

! -path "./100/[ab].txt" ! -path ./100/foo

Это не найдет a.txtили b.txtили foo, но он найдет все другие файлы.

Когда вы уверены, что видите, что хотите, вы можете добавить -deleteв конец, чтобы удалить найденные файлы:

find ! -path . ! -path ./100 ! -path ./101 ! -path "./100/[ab].txt" ! -path "./101/[cd].txt" -delete
Занна
источник