Unix - usuń pliki i foldery z wyjątkiem WZORCA

10

Ostatnio stanąłem przed zadaniem usunięcia wszystkich plików / folderów z katalogu oprócz tych pasujących do określonego wzorca. Przygotowałem więc jednoliniowe polecenie unixowe do wykonania pracy. Czy to musi być tylko jedna linia? Chyba nie, ale w ten sposób jest zdecydowanie chłodniej!

Chociaż problem jest dość prosty, byłem trochę zaskoczony, jak skomplikowane stało się moje rozwiązanie. Oto polecenie, którego użyłem; UWAGA: jest to złe rozwiązanie, ponieważ nie obsługuje nazw plików zawierających znaki przesunięcia wiersza (co nie miało znaczenia w mojej sytuacji).

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

Nie użyłem polecenia „znajdź”, ponieważ nie chcę się ponownie zapisywać w folderach pasujących do WZORCA. Rozważmy na przykład następującą strukturę plików:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

Użycie wzorca „foo” musi usuwać tylko „first_dir” (i oczywiście jego zawartość) oraz „somefile.txt” ( nie „anotherfile.txt” ani „morefiles.log”).

Pytanie, czy są lepsze (bardziej eleganckie i poprawne) sposoby na osiągnięcie tego?


EDYCJA:
Ostatnio zwrócono mi uwagę, że lepszym rozwiązaniem może być „znajdź” :

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

To rozwiązanie poprawnie obsługuje ścieżki zawierające znaki nowego wiersza.

joxl
źródło
EDYCJA: zmieniono błędny „katalog”, aby poprawić „katalog pierwszy”.
joxl

Odpowiedzi:

10

Poniższe przykłady mają echoprefiks, dzięki czemu można przetestować wzorce przed ich użyciem. Usuń, echoaby aktywować rm -rf. Zastąp rm -riprośbę o potwierdzenie.

ksh ma rozszerzenie dopasowania ujemnego do globowania:

# ksh
echo rm -rf !(*foo*)

Ta sama składnia jest dostępna w bash, jeśli ustawisz extglobopcję:

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh ma do tego swoją własną składnię:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

Może także używać składni w stylu ksh :

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))
Chris Johnsen
źródło
Prosty, elegancki, obsługuje znaki wiersza, (prawie) jedną linię (dodałem shopt -s extglobdo mojego pliku .bashrc, więc teraz jest to jednowierszowy). Doskonały! Obiecuję głosowanie, gdy tylko moja reputacja na to pozwoli.
joxl
7

Oto inne findrozwiązanie. Nie jestem pewien, czy ma to jakąś rzeczywistą przewagę nad twoją, ale nie potrzebuje xargsi pozwala na rzadką możliwość, że * rozszerza się na zbyt wiele nazw.

find . -maxdepth 1 ! -name PATTERN -type f -delete

Dodałem również -type f, aby nie próbowało usuwać katalogów.

Ostrzeżenie: -deletejest potężny. Dałem jednemu z moich plików testowych 0 uprawnień, a powyższe polecenie usunęło je bez wahania.

garyjohn
źródło
6
Najpierw przetestuj. Wymień -deletesię -print, aby zobaczyć, czy to ze znalezieniem plików chciałeś. Jeśli wszystko jest w porządku, użyj historii poleceń (np. Naciśnij przycisk w górę), aby wrócić do poprzedniego polecenia i upewnić się, że pracujesz z tymi samymi filtrami wyszukiwania.
Doug Harris
Czytaj uważnie, uwaga, że zrobić chęć katalogów usunąć. I find -deletenie usunie niepustych katalogów. Zauważ też, że find -maxdepth 1pasuje do „.” (bieżący katalog), co jest naprawdę złe. Chociaż podoba mi się twój pomysł wyeliminowania xargs, można użyć find -execalternatywnie. find * -maxdepth 0 ! -name PATTERN -exec rm -rf '{}' \;
joxl
0

Zamiast tego możesz użyć tego przykładu skryptu zbrojenia http://askcodegeneration.com/keep-subversion/, który jest znacznie bardziej zrozumiały i który może zarządzać interakcją użytkownika, taką jak wybór folderu i potwierdzenie:

delete-file: func[file][
    if/else none? find file "/.svn/" [
        delete file
    ][
        print ["keeping" file]
    ]
]
dir: request-dir
ans: ask rejoin ["Do you confirm " dir "? (Yes): "]
if (ans = "Yes") [
    foreach-file dir :delete-file
]
Samouczek Rebol
źródło