Usuń wszystkie pliki oprócz niektórych z katalogu


215

Podczas używania sudo rm -r, w jaki sposób mogę usunąć wszystkie pliki, z wyjątkiem następujących:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

5
Brzmi jak pytanie do unix.stackexchange.com
Jason

1
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:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

na przykład usuń wszystkie pliki inne niż txt z bieżącego katalogu:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

print0I -0potrzebna jest kombinacja jeśli istnieją przestrzenie w którymkolwiek z nazwami plików, które powinny zostać usunięte.


2
wydaje się, że xargs ma limit rozmiaru tekstu
frazras

26
aby usunąć wiele wzorów:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
Siwei Shen 申思维

5
co z katalogami? usunie wszystkie pliki, ale czy usunie foldery ?!
orezvani

31
Zamiast "| xargs rm", find przyjmuje parametr -delete.
Emil Stenström,

1
zamiast -print0 | xargs -0 rm --ciebie możesz po prostu-delete
Andy

151
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

Extglob (Extended Match Matching) musi być włączony w BASH (jeśli nie jest włączony):

shopt -s extglob

2
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 interaktywnej bash 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.
Ahresse

41

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ć:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

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.


2
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

19

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 -

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

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.


6
+1; Prostszą alternatywą dla ustawiania i przywracania GLOBIGNOREzmiennej jest użycie podpowłoki:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0

19

Wolę używać listy zapytań podrzędnych:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v, - odwróć dopasowanie wybierz niepasujące linie

\| Separator


1
Eleganckie rozwiązanie
Joshua Salazar

9

Ponieważ nikt o tym nie wspominał:

  • skopiuj pliki, których nie chcesz usunąć w bezpieczne miejsce
  • usuń wszystkie pliki
  • przenieś skopiowane pliki z powrotem na miejsce

2
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 *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;

6

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ć)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

np. aby usunąć wszystko oprócz plików tekstowych i foo.bar:

rm_except *.txt foo.bar 

Podobne do @mishunika, ale bez klauzuli if.


5

Jeśli używasz tego, zshco gorąco polecam.

rm -rf ^file/folder pattern to avoid

Z extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

4

Wypróbowanie go zadziałało z:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

ale nazwy ze spacjami są (jak zawsze) trudne. Próbowałem także z Virtualbox\ VMscytatami. Usuwa zawsze ten katalog ( Virtualbox VMs).


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

Lub:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

Nie jest to zalecane. Przetwarzanie lsdanych wyjściowych może stać się problemem. Zobacz tutaj, aby uzyskać szczegółowe informacje.
RJ

2

Spraw, aby pliki były niezmienne. Nawet root nie będzie mógł ich usunąć.

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

Wszystkie inne pliki zostały usunięte.
W końcu możesz je zresetować.

chattr -i *

0

Jest to podobne do komentarza z @ siwei-shen, ale potrzebujesz -oflagi, aby wykonać wiele wzorców. -oFlaga oznacza „lub”

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm


0

Możesz to zrobić za pomocą dwóch sekwencji poleceń. Najpierw zdefiniuj tablicę z nazwą plików, których nie chcesz wykluczyć:

files=( backup.tar.gz script.php database.sql info.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 *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

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:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

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)


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

2
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
RJ
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.