Z wyłączeniem niektórych plików i katalogów podczas usuwania plików

11

Mój katalog najwyższego poziomu to data. datazawiera kilka katalogów i te katalogi mają podkatalogi. Muszę usunąć wszystkie pliki i katalogi wewnątrz, data/z wyjątkiem kilku plików w niektórych katalogach.

Na przykład dane obejmują katalogi 100i 101. Chcę tylko zachować a.txti b.txtpliki w 100/i c.txti d.txtpliki w 101/podczas usuwania wszystkich innych plików i katalogów w 100i 101.

Przykład:

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

Korzystam z rm -rf !(a.txt|b.txt)polecenia, ale nie mogę zastosować go automatycznie do każdego katalogu.

Głęboki błękit
źródło

Odpowiedzi:

12

Jak już się dowiedziałeś, możesz skorzystać z extglobfunkcji, która jest włączona w:

shopt -s extglob

Umożliwia to wykluczanie dopasowań, dzięki czemu można wykonywać takie czynności, jak:

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

Warto echonajpierw przetestować . Ten przykład pasuje do wszystkiego, 100/co jest wewnątrz a.txtlub nie, b.txti do wszystkiego, 101/co nie jest c.txtlub d.txt. Jeśli 100/obowiązują 102/Cię te same zasady , możesz np .:

10[02]/!([ab].txt) # or
{100,102}/!([ab].txt)
deser
źródło
Właśnie podałem przykład dla 100 i 101 katalogów, ale w rzeczywistości liczba podkatalogów wynosi prawie 20. Czy istnieje sposób na wdrożenie powyższego kodu dla każdego katalogu bez zapisywania nazw katalogów w folderze głównym?
deepblue
@deepblue Podaj dokładny przykład tego w swoim pytaniu ( edytuj ), szczególnie niejasne jest, w jaki sposób rmnależy wiedzieć, które pliki przechowywać w których katalogach, jeśli nie chcesz tego określać.
deser
7

Możesz finddo tego użyć . Możesz zanegować testy za findpomocą -notlub !. Spowoduje to wykluczenie dopasowań zamiast ich znajdowania.

Należy uważać, aby nie usunąć żadnego z nadrzędnych katalogów plików, które chcesz zachować, zwłaszcza bieżącego katalogu . , więc upewnij się, że dokładnie przeczytałeś dane wyjściowe przed usunięciem.

Na podstawie twojego przykładu możesz zrobić coś takiego z datakatalogu.

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

Dodaj ! -path ./path/to/dirdowolną ścieżkę, której chcesz uniknąć. Możesz używać metaznaków, takich jak *, ale pamiętaj o zacytowaniu wyrażenia, jeśli tak zrobisz, np. "./path*dir"Aby zapobiec niepożądanym rozszerzeniom.

findjest domyślnie rekurencyjny. Nawet jeśli nie znajdziemy ./100tutaj, znajdziemy całą jego zawartość, chyba że pasują do wzorca [ab].txt. Jeśli nie możesz dopasować wszystkich nazw, które chcesz zachować, dodaj kolejny test:

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

To nie znajdzie a.txtalbo b.txtalbo foo, ale znajdzie wszystkie inne pliki.

Gdy jesteś pewien, że widzisz, co chcesz, możesz dodać -deletena końcu, aby usunąć znalezione pliki:

find ! -path . ! -path ./100 ! -path ./101 ! -path "./100/[ab].txt" ! -path "./101/[cd].txt" -delete
Zanna
źródło