Istnieją dwa sposoby odczytania tego pytania, a istniejące odpowiedzi obejmują obie interpretacje: EITHER: (a) zachowaj pliki o określonych nazwach bezpośrednio znajdujące się w katalogu docelowym i - jak to rm -rsugeruje - usuń wszystko inne, w tym podkatalogi - nawet jeśli zawierają pliki o określonych nazwach; LUB: (b) przejdź przez całe poddrzewo katalogu docelowego i, w każdym katalogu, usuń wszystkie pliki oprócz tych z wymienionymi nazwami.
mklement0
Odpowiedzi:
219
find [path]-type f -not -name 'textfile.txt'-not -name 'backup.tar.gz'-delete
Jeśli nie określisz, -type ffind wyświetli również katalogi, których możesz nie chcieć.
Lub bardziej ogólne rozwiązanie przy użyciu bardzo przydatnej kombinacji find | xargs:
Dostaję „błąd składni w pobliżu nieoczekiwanego tokena„ (”), gdy to robię shopt -s extglob; rm -rf !(README|LICENSE). Wiesz, dlaczego?
Dennis
@nic Nie pamiętam, przepraszam. I prawdopodobnie skończyło się findwraz z -deleteopcją.
Dennis
To jest najlepsze rozwiązanie dla mnie i działa domyślnie na moim Ubuntu 12.04.4 LTS bez potrzeby shopt
xtian
3
@nic, @Dennis: Błąd składniowy sugeruje, że bashużyto INNEGO niż użyto, np. dashgdzie extglobnie jest obsługiwane. Jednak w interaktywnejbash powłoce polecenie TAKŻE nie będzie działać, jak podano, choć z różnych powodów. Krótko mówiąc: wykonaj shopt -s extglobsamodzielnie. RAZ ZAKOŃCZYŁ SIĘ BEZPIECZNIE (sprawdź za pomocą shopt extglob), wykonaj rm -rf !(README|LICENSE). (Chociaż extglobnie jest jeszcze włączony, !(...)jest oceniany przez rozwinięcie historii PRZED wykonaniem poleceń; ponieważ prawdopodobnie to się nie powiedzie, polecenie extglob
NIGDY
2
@nic, @Dennis, @ mklement0: Miałem ten sam problem z „błędem składni w pobliżu nieoczekiwanego tokena (” podczas wykonywania polecenia w pliku .sh (#! / bin / bash), ale nie wtedy, gdy działałem w poleceniu Okazało się, że oprócz shopt -s extgloburuchomienia w interfejsie wiersza poleceń musiałem ponownie uruchomić go w pliku skryptu. To rozwiązało problem dla mnie.
Spowoduje to wyświetlenie listy wszystkich plików w bieżącym katalogu, a następnie wszystkich tych, które nie spełniają Twoich kryteriów (uważaj, aby pasowały do nazw katalogów), a następnie usuń je.
Aktualizacja : na podstawie dokonanej edycji, jeśli naprawdę chcesz usunąć wszystko z bieżącego katalogu oprócz wymienionych plików, możesz tego użyć:
Stworzy katalog kopii zapasowej /tmp_backup(masz uprawnienia roota, prawda?), Przeniesie wymienione pliki do tego katalogu, usunie rekurencyjnie wszystko w bieżącym katalogu (wiesz, że jesteś we właściwym katalogu, prawda?), Przeniesiesz z powrotem do bieżącego katalogu wszystko /tmp_backupi na koniec usuń /tmp_backup.
Wybieram katalog kopii zapasowej jako root, ponieważ jeśli próbujesz usunąć wszystko rekurencyjnie z roota, twój system będzie miał duże problemy.
Z pewnością istnieją bardziej eleganckie sposoby na zrobienie tego, ale ten jest dość prosty.
Działa również bardzo dobrze z egrep, np. Do czyszczenia pośrednich plików lateksowych:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz
niesamowite polecenie! do usuwania katalogów wystarczy zmienić na rm -r
Aris
1
Jeśli chcesz po prostu usunąć wszystko w bieżącym katalogu oprócz kryteriów wykluczonych: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rdziała znacznie szybciej, ponieważ nie trzeba niepotrzebnie wchodzić do katalogów.
billynoah
Re findpipeline: pomijając kwestie wydajności (3 polecenia są używane do tego, co findmożna zrobić samodzielnie), nie będzie to działać zgodnie z przeznaczeniem w nazwach plików z osadzonymi spacjami i potencjalnie usunie nieprawidłowe pliki.
mklement0
Polecenie przechowujące pliki „do zapisania” w innym miejscu ( /tmp_backup) nie kończy się dobrze, jeśli zostanie przerwane - z perspektywy użytkownika wszystkie pliki zniknęły, chyba że wiedzą, gdzie je znaleźć, aby je odzyskać . Z tego powodu nie jestem zwolennikiem tego typu strategii.
Craig McQueen
20
Zakładając, że pliki o tych nazwach istnieją w wielu miejscach w drzewie katalogów i chcesz je wszystkie zachować:
find .-type f !-regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)"-delete
Ustawienie GLOBIGNORE w ten sposób ignoruje php i sql z symboli wieloznacznych używanych, takich jak „ls *” lub „rm *”. Zatem użycie „rm *” po ustawieniu zmiennej spowoduje usunięcie tylko pliku txt i tar.gz.
Jest to bardziej skomplikowane, ponieważ musisz zadbać o uprawnienia po ich skopiowaniu.
Romulus
2
@RemusAvram Możesz użyć odpowiednich przełączników z cplub, rsyncaby zachować uprawnienia. W każdym razie jest to tylko metoda alternatywna (podana jako sugestia), która ma swoje miejsce tutaj, jako odpowiedź na PO.
gniourf_gniourf
Może to nie być odpowiednie w wielu sytuacjach, w których przechowywane pliki są aktywnie wykorzystywane przez inne procesy. Uciążliwe jest również to, że pliki do usunięcia to tylko niewielki podzbiór i w grę wchodzi duża liczba plików.
codeforester
@codeforester: pewnie. Ale są sytuacje, w których jest to właściwe, ale ... tak naprawdę nie widzę sensu twojego komentarza :).
gniourf_gniourf
6
Możesz napisać pętlę for dla tego ...%)
for x in*doif["$x"!="exclude_criteria"]then
rm -f $x;fidone;
Trochę za późno na OP, ale mam nadzieję, że przydatne dla każdego, kto dotrze tu znacznie później przez Google ...
Znalazłem odpowiedź @awi i komentarz na -delete @Jamie Bullock jest bardzo przydatny. Proste narzędzie, dzięki któremu można to zrobić w różnych katalogach, ignorując za każdym razem różne nazwy / typy plików przy minimalnym wpisywaniu:
NIE działa dla plików. rm !(myfile.txt)usuwa wszystkie, w tymmyfile.txt
khaverim
powinien wykonać shopt -s extglobnajpierw, jak wskazał @ pl1nk
zhuguowei
Tak, bardzo ważne jest, aby aktywować rozszerzone globbing ( extglob ) w bash, robię to codziennie, na kilku komputerach Mac w laboratoriach: shopt -s extgloba potem w cd /Users/alumno/końcu rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) przeczytaj o rozszerzonym globowaniu tutaj
juanfal
4
Właśnie:
rm $(ls -I "*.txt")#Deletes file type except *.txt
Następnie przejrzyj wszystkie pliki w katalogu, który chcesz wykluczyć, sprawdzając, czy nazwa pliku znajduje się w tablicy, której nie chcesz wykluczyć; jeśli nie, usuń plik.
for file in*;doif[[!" ${files[@]} "~="$file"]];then
rm "$file"fidone
Porównanie wyrażeń regularnych jest niepoprawne - zachowa każdy plik, którego nazwa jest podciągiem jednego z chronionych plików (chociaż otaczające go spacje nieco to łagodzą, ale nazwy plików mogą zawierać spacje). Powinieneś zebrać tablicę wszystkich plików, następnie odjąć pliki, które chcesz wykluczyć z tej tablicy, a następnie usunąć pozostałe pliki.
tripleee
-1
Ponieważ nikt jeszcze o tym nie wspominał, w jednym szczególnym przypadku:
OLD_FILES=`echo *`... create new files ...
rm -r $OLD_FILES
(lub po prostu rm $OLD_FILES)
lub
OLD_FILES=`ls *`... create new files ...
rm -r $OLD_FILES
Może być konieczne użycie, shopt -s nullglobjeśli niektóre pliki mogą być tam albo nie:
Istniejąca odpowiedź Leonarda Hermoso robi to z mniejszą liczbą błędów. Nie powiedzie się to dla nazw plików ze spacjami; użycie tablicy elegancko rozwiązuje ten konkretny problem (a także w mniejszym stopniu unika używania wielkich liter w swoich prywatnych zmiennych, których ogólnie należy unikać).
tripleee
-3
Zamiast wybierać bezpośrednie polecenie, przenieś wymagane pliki do katalogu temp poza aktualny katalog. Następnie usuń wszystkie pliki za pomocą rm *lubrm -r * .
Następnie przenieś wymagane pliki do bieżącego katalogu.
Może to nie być odpowiednie w wielu sytuacjach, w których przechowywane pliki są aktywnie wykorzystywane przez inne procesy. Uciążliwe jest również to, że pliki do usunięcia to tylko niewielki podzbiór i w grę wchodzi duża liczba plików.
codeforester
-3
Usuń wszystko wyklucz plik.nazwa:
ls -d /path/to/your/files/*|grep -v file.name|xargs rm -rf
To zawiedzie okropnie i może spowodować utratę danych, jeśli twój katalog / pliki mają spacje lub nietypowe znaki. Nigdy nie powinieneś analizować ls. mywiki.wooledge.org/ParsingLs
rm -r
sugeruje - usuń wszystko inne, w tym podkatalogi - nawet jeśli zawierają pliki o określonych nazwach; LUB: (b) przejdź przez całe poddrzewo katalogu docelowego i, w każdym katalogu, usuń wszystkie pliki oprócz tych z wymienionymi nazwami.Odpowiedzi:
Jeśli nie określisz,
-type f
find wyświetli również katalogi, których możesz nie chcieć.Lub bardziej ogólne rozwiązanie przy użyciu bardzo przydatnej kombinacji
find | xargs
:na przykład usuń wszystkie pliki inne niż txt z bieżącego katalogu:
print0
I-0
potrzebna jest kombinacja jeśli istnieją przestrzenie w którymkolwiek z nazwami plików, które powinny zostać usunięte.źródło
find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
-print0 | xargs -0 rm --
ciebie możesz po prostu-delete
Extglob (Extended Match Matching) musi być włączony w BASH (jeśli nie jest włączony):
źródło
shopt -s extglob; rm -rf !(README|LICENSE)
. Wiesz, dlaczego?find
wraz z-delete
opcją.bash
użyto INNEGO niż użyto, np.dash
gdzieextglob
nie jest obsługiwane. Jednak w interaktywnejbash
powłoce polecenie TAKŻE nie będzie działać, jak podano, choć z różnych powodów. Krótko mówiąc: wykonajshopt -s extglob
samodzielnie. RAZ ZAKOŃCZYŁ SIĘ BEZPIECZNIE (sprawdź za pomocąshopt extglob
), wykonajrm -rf !(README|LICENSE)
. (Chociażextglob
nie jest jeszcze włączony,!(...)
jest oceniany przez rozwinięcie historii PRZED wykonaniem poleceń; ponieważ prawdopodobnie to się nie powiedzie, polecenieextglob
shopt -s extglob
uruchomienia w interfejsie wiersza poleceń musiałem ponownie uruchomić go w pliku skryptu. To rozwiązało problem dla mnie.find . | grep -v "excluded files criteria" | xargs rm
Spowoduje to wyświetlenie listy wszystkich plików w bieżącym katalogu, a następnie wszystkich tych, które nie spełniają Twoich kryteriów (uważaj, aby pasowały do nazw katalogów), a następnie usuń je.
Aktualizacja : na podstawie dokonanej edycji, jeśli naprawdę chcesz usunąć wszystko z bieżącego katalogu oprócz wymienionych plików, możesz tego użyć:
Stworzy katalog kopii zapasowej
/tmp_backup
(masz uprawnienia roota, prawda?), Przeniesie wymienione pliki do tego katalogu, usunie rekurencyjnie wszystko w bieżącym katalogu (wiesz, że jesteś we właściwym katalogu, prawda?), Przeniesiesz z powrotem do bieżącego katalogu wszystko/tmp_backup
i na koniec usuń/tmp_backup
.Wybieram katalog kopii zapasowej jako root, ponieważ jeśli próbujesz usunąć wszystko rekurencyjnie z roota, twój system będzie miał duże problemy.
Z pewnością istnieją bardziej eleganckie sposoby na zrobienie tego, ale ten jest dość prosty.
źródło
find . | egrep -v "\.tex|\.bib" | xargs rm
find . -maxdepth 1 | grep -v "exclude these" | xargs rm -r
działa znacznie szybciej, ponieważ nie trzeba niepotrzebnie wchodzić do katalogów.find
pipeline: pomijając kwestie wydajności (3 polecenia są używane do tego, cofind
można zrobić samodzielnie), nie będzie to działać zgodnie z przeznaczeniem w nazwach plików z osadzonymi spacjami i potencjalnie usunie nieprawidłowe pliki./tmp_backup
) nie kończy się dobrze, jeśli zostanie przerwane - z perspektywy użytkownika wszystkie pliki zniknęły, chyba że wiedzą, gdzie je znaleźć, aby je odzyskać . Z tego powodu nie jestem zwolennikiem tego typu strategii.Zakładając, że pliki o tych nazwach istnieją w wielu miejscach w drzewie katalogów i chcesz je wszystkie zachować:
źródło
Możesz użyć zmiennej środowiskowej GLOBIGNORE w Bash.
Załóżmy, że chcesz usunąć wszystkie pliki oprócz php i sql, a następnie możesz wykonać następujące czynności -
Ustawienie GLOBIGNORE w ten sposób ignoruje php i sql z symboli wieloznacznych używanych, takich jak „ls *” lub „rm *”. Zatem użycie „rm *” po ustawieniu zmiennej spowoduje usunięcie tylko pliku txt i tar.gz.
źródło
GLOBIGNORE
zmiennej jest użycie podpowłoki:(GLOBIGNORE='*.php:*.sql'; rm *)
Wolę używać listy zapytań podrzędnych:
źródło
Ponieważ nikt o tym nie wspominał:
źródło
cp
lub,rsync
aby zachować uprawnienia. W każdym razie jest to tylko metoda alternatywna (podana jako sugestia), która ma swoje miejsce tutaj, jako odpowiedź na PO.:)
.Możesz napisać pętlę for dla tego ...%)
źródło
Trochę za późno na OP, ale mam nadzieję, że przydatne dla każdego, kto dotrze tu znacznie później przez Google ...
Znalazłem odpowiedź @awi i komentarz na -delete @Jamie Bullock jest bardzo przydatny. Proste narzędzie, dzięki któremu można to zrobić w różnych katalogach, ignorując za każdym razem różne nazwy / typy plików przy minimalnym wpisywaniu:
rm_except (lub jakkolwiek chcesz to nazwać)
np. aby usunąć wszystko oprócz plików tekstowych i foo.bar:
Podobne do @mishunika, ale bez klauzuli if.
źródło
Jeśli używasz tego,
zsh
co gorąco polecam.Z
extended_glob
źródło
Wypróbowanie go zadziałało z:
ale nazwy ze spacjami są (jak zawsze) trudne. Próbowałem także z
Virtualbox\ VMs
cytatami. Usuwa zawsze ten katalog (Virtualbox VMs
).źródło
rm !(myfile.txt)
usuwa wszystkie, w tymmyfile.txt
shopt -s extglob
najpierw, jak wskazał @ pl1nkshopt -s extglob
a potem wcd /Users/alumno/
końcurm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library)
przeczytaj o rozszerzonym globowaniu tutajWłaśnie:
Lub:
źródło
ls
danych wyjściowych może stać się problemem. Zobacz tutaj, aby uzyskać szczegółowe informacje.Spraw, aby pliki były niezmienne. Nawet root nie będzie mógł ich usunąć.
Wszystkie inne pliki zostały usunięte.
W końcu możesz je zresetować.
źródło
Jest to podobne do komentarza z @ siwei-shen, ale potrzebujesz
-o
flagi, aby wykonać wiele wzorców.-o
Flaga oznacza „lub”find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm
źródło
Możesz to zrobić za pomocą dwóch sekwencji poleceń. Najpierw zdefiniuj tablicę z nazwą plików, których nie chcesz wykluczyć:
Następnie przejrzyj wszystkie pliki w katalogu, który chcesz wykluczyć, sprawdzając, czy nazwa pliku znajduje się w tablicy, której nie chcesz wykluczyć; jeśli nie, usuń plik.
źródło
Ponieważ nikt jeszcze o tym nie wspominał, w jednym szczególnym przypadku:
(lub po prostu
rm $OLD_FILES
)lub
Może być konieczne użycie,
shopt -s nullglob
jeśli niektóre pliki mogą być tam albo nie:bez nullglob,
echo *.sh *.bash
może dać ci „a.sh b.sh * .bash”.(Powiedziawszy to wszystko, sam wolę tę odpowiedź , nawet jeśli nie działa ona w OSX)
źródło
Zamiast wybierać bezpośrednie polecenie, przenieś wymagane pliki do katalogu temp poza aktualny katalog. Następnie usuń wszystkie pliki za pomocą
rm *
lubrm -r *
.Następnie przenieś wymagane pliki do bieżącego katalogu.
źródło
Usuń wszystko wyklucz plik.nazwa:
źródło