Jak usunąć wszystkie pliki w katalogu oprócz niektórych?

123

Muszę usunąć wszystkie pliki z katalogu, ale wykluczyć niektóre z nich. Na przykład w katalogu z plikami a b c ... zmuszę usunąć wszystkie oprócz ui p. Czy jest na to łatwy sposób?

Strzał
źródło
Poniższe odpowiedzi są o wiele lepsze, ale możesz po prostu sprawić, by pliki zapisywały tylko do odczytu, usuwały wszystkie, a następnie przywracały je do pierwotnych uprawnień (o ile nie używasz rm -f). Musisz wiedzieć, jakie uprawnienia przywrócić, i musisz wiedzieć, że podczas procesu nic nie wymagało dostępu do zapisu. Dlatego inne odpowiedzi są lepsze.
Joe
1
Jeśli chcesz również usunąć ukryte pliki, uruchom shopt -s dotglobprzed uruchomieniem rm (...).

Odpowiedzi:

108

W tych przypadkach piszę

rm *

Następnie naciskam Ctrl+ X, *aby rozwinąć * do wszystkich widocznych nazw plików.

Następnie mogę po prostu usunąć z listy dwa pliki, które chcę zachować, i na koniec uruchomić wiersz poleceń.

Der Hochstapler
źródło
25
Wydaje mi się, że to działa tylko tak długo, jak długo lista plików, która się *rozwija, nie jest zbyt długa. : -}
Frerich Raabe
9
Esc, po którym następuje *, również rozszerzy „*”.
slowpoison
2
@SantoshKumar: To nie ma dla mnie sensu. Rozszerzenie zawsze będzie działać, nie zależy od tego, którego polecenia chcesz użyć później.
Der Hochstapler
2
@OliverSalzburg Przepraszamy, kombinacja jest trochę myląca. Myślę, że powinieneś pisać jak Ctrl+ Shift+ x+*
Santosh Kumar
2
@SantoshKumar: Ale to nie jest kombinacja.
Der Hochstapler,
143

Do rmwszystkich oprócz u,pbash wystarczy wpisać:

rm !(u|p)

Wymaga to ustawienia następującej opcji:

shopt -s extglob

Zobacz więcej: glob - Wiki Grega

sparkie
źródło
1
musisz mieć aktywną funkcję „extglobbing”: shopt -s extglob
sparkie
18
Musisz shopt -s extglob, @Ashot. Poza tym to tylko pliki, a nie katalogi, dlatego usunąłem -rfopcje z twojego polecenia.
slhck
3
Jeśli trzeba wykluczyć jeden plik z wyborem plików, spróbuj tego: rm !(index).html. Spowoduje to usunięcie wszystkich plików z rozszerzeniem „.html”, z wyjątkiem „index.html”.
mzuther
71

Możesz użyć find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! neguje następne wyrażenie
  • -name określa nazwę pliku
  • -maxdepth 1spowoduje, że find przetworzy tylko podany katalog ( finddomyślnie katalogi przechodzą)
  • -type f będzie przetwarzać tylko pliki (a nie na przykład katalogi)
  • -delete usunie pliki

Następnie możesz dostroić warunki, patrząc na stronę podręcznika wyszukiwania

Aktualizacja

  • Należy pamiętać, że kolejność elementów wyrażeń jest znacząca (patrz dokumentacja)
  • Przetestuj najpierw swoje polecenie, używając -printzamiast-delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print
Matteo
źródło
5
kolejność predykatów ma tutaj kluczowe znaczenie. Jeśli jedno wstawione -deletezaraz po .nim będzie katastrofą (usunie wszystkie pliki w CWD)
Michał Šrajer
Można to zapisać bardziej find . -maxdepth 1 -type f -name '[^up]' -delete
zwięźle
4
@kojiro tak, ale tylko w przypadku plików zawierających tylko jedną literę. Przy bardziej złożonych nazwach wyrażenie regularne może być bałaganem.
Matteo,
2
findjest moim najlepszym przyjacielem, zwłaszcza gdy jest zbyt wiele plików do glob
Terence Johnson
43

Prosty:

mvpliki, które chcesz w górnym katalogu, rmw katalogu, a następnie z mvpowrotem.

użytkownik176581
źródło
13
Offcourse, mv je do katalogu wyżej. Staraj się nie przenosić ich do podkatalogu, który usuwasz ...
Konerak
@Konerak: rmbez -rnie usunie podkatalogów.
reinierpost
11
Spowoduje to zastąpienie plików o tej samej nazwie w katalogu docelowym
Matteo
7
Głosuję za tym, ponieważ chociaż może być przydatny, jest także nieatomowy i skutecznie usuwa wszystkie pliki z katalogu w krótkim okresie czasu; byłoby to nie do przyjęcia, jeśli na przykład pliki są udostępniane w sieci.
sam hocevar
15

Trochę podobne do tej odpowiedzi, ale nie są potrzebne żadne specjalne opcje, o ile wiem, że „starożytna” funkcjonalność jest obsługiwana przez dowolną (niejasno) / bin / sh przypominającą powłokę (np. Bash, zsh, ksh itp.)

rm [^up]
hlovdal
źródło
2
Działa to dla nazw plików 1-znakowych. W przypadku dłuższych nazw odpowiedź sparkie jest lepsza.
glenn jackman
3
Co byłoby nie tak rm [^up]*? Często robię podobne rzeczy.
CVn
3
@ MichaelKjörling - spowoduje to usunięcie wszystkich plików zaczynających się od u lub p, nie tylko tych o nazwach u i p. Myślę, że OP (@Ashot) oznaczało az i u, p itd. symbolicznie i nie dosłownie.
Sudipta Chatterjee
4
@HobbesofCalvin To usunie wszystkie pliki, które nie zaczynają się od u lub p, a nie te, które zaczynają się od nich.
rjmunro
@rjmunro - dzięki, przegapiłem ten! :)
Sudipta Chatterjee
11

Robiąc to bez znalezienia:

ls | grep -v '(u|p)' | xargs rm

(Edycja: „u” i „v”, podobnie jak w innych miejscach tutaj, są używane jako ogólne wersje całych wyrażeń regularnych. Oczywiście musisz zachować ostrożność, aby zakotwiczyć wyrażenia regularne, aby uniknąć dopasowania zbyt wielu rzeczy.)

Zdecydowanie będziesz potrzebować skryptu, jeśli będziesz robić dużo z tego, jak sugerowali inni.

kałamarnica
źródło
grep domyślnie nie obsługuje rozszerzonego wyrażenia regularnego: użyj -Ealboegrep
Matteo
2
będzie to wykluczyć plik zawierający ulubp
Matteo
@Matteo Nie, nie będzie. Grep nie grepuje plików, to grepuje wyjście polecenia ls. Zastanawiasz się nad tym, grep -L (u|p)' * | xargs rmgdzie -Loznacza, że ​​nazwy plików list nie zawierają dopasowania.
rjmunro
4
Och, masz na myśli każdy plik, którego nazwa zawiera ulub pżaden plik zawierający a ulub a p. To jest poprawne. Możesz to naprawić za pomocąegrep -v '^(u|p)$'
rjmunro,
1
Tutaj usuwa się wszystko oprócz tych dopasowań! ls | grep -v 'vuze\|progs' | xargs rm -rf
Nick
6

W Zsh:

setopt extended_glob  # probably in your .zshrc

następnie

rm ^(u|p)

lub

rm *~(u|p)

Drugi będzie działać nawet jeśli masz ^w $histcharsHistorii substytucji, i oczywiście można umieścić dowolną glob przed ~.

poolie
źródło
5

GLOBIGNORE przyjmuje listę rozdzieloną dwukropkami

GLOBIGNORE=u:p
rm *
W_Whalley
źródło
12
To nie działa na mojej powłoce (GNU bash 4.1.5 (1)). Najpierw przetestuj go z czymś nieco mniej szkodliwym niżrm w katalogu testowym!
CVn
3

W erze dyskietek miałem plik wykonywalny dos o nazwie „Z wyjątkiem”, który tymczasowo przenosiłby rzeczy z bieżącego katalogu i wykonywał polecenie, aby można było powiedzieć:

oprócz * .txt del *. *

aby usunąć wszystko oprócz plików tekstowych.

Byłoby to dość trywialne zaimplementowanie jako skrypt powłoki, a jeśli jest to coś, co możesz zrobić więcej niż dwa razy, wydaje się, że byłby to dobry pomysł.

Bill K.
źródło
2
Przypomniało mi to samo. Ale tymczasowe wyprowadzenie się z folderu może nie być dobrym pomysłem w erze wielozadaniowości :)
Sedat Kapanoglu
3
 find . -maxdepth 1 ! -name "u" ! -name "p" -type f -exec rm -rf {} \;

Spowoduje to usunięcie wszystkich plików oprócz u i p w unixie

użytkownik1803687
źródło
2

Dla tych, którzy wolą określać dowolne złożone wzorce wykluczania (obejmujące wszystkie zmienione nazwy plików) w pełnym stylu emacs wyrażenia regularnego, posix-awk lub rozszerzonym posix-em (zobacz stronę man) polecam ten. W tym przykładzie wyklucza uiw pobecnym reż. Może to być przydatne w przypadku skryptów.

find -regextype posix-awk ! -regex './(u|p)' -print0 | xargs -0 rm -rf
sparkie
źródło
Musisz podać katalog przed wyrażeniem (`find. -Regextype ...).
Matteo,
-regextypebędzie działać tylko na wersjach GNU
Matteo
no - moja wersja find (ściśnięcie Debiana) definitywnie nie wymaga jawnego katalogu przed wyrażeniem, jeśli należy użyć bieżącego katalogu
sparkie
@sparke: działa to tylko w przypadku implementacji GNU
Matteo
@sparkie: brak zdefiniowania katalogu (pierwszego parametru) findjest rozszerzeniem findpolecenia GNU . To samo dotyczy -regextypeopcji. Ponadto twoje polecenie usunie również pliki z podkatalogów, podczas gdy pierwotne pytanie wyraźnie zadawało pytania dotyczące plików w katalogu.
Mikko Rantalainen,
1

Zawsze używam:

rm [a-o,q-t,v-z]*

Umożliwi to określenie stopnia szczegółowości. Jeśli więc chcesz usunąć pliki od O do Z, możesz użyć:

rm [a-o,z]*
J Baron
źródło
1

Jeszcze inna wersja wykorzystująca xargs:

ls -1 | grep -v do_not_delete | xargs -I files rm "files"

Należy pamiętać, że xargs -Ijest to potrzebne do poprawnego obsługiwania nazw plików, w tym spacji.

Sebhofer
źródło
1

Jeszcze inny:

for FILE in ./*; do if [[ $FILE != ./u* ]] || [[ $FILE != ./p* ]];then rm $FILE; fi; done;

Jest to dość długie i nie wiem, czy można łatwo przekształcić go w funkcję, która z łatwością pomieści dowolną liczbę argumentów, ale działa dobrze.

I to czysta dobroć.

dylnmc
źródło
1

Oto inny wariant. Możesz pisać:

rm -i *

lub:

rm --interactive *

Więc rmpoprosi, aby potwierdzić usunięcie każdego pliku.

idzikovsky
źródło
1

Posługiwać się:

find . -type f ! -name 'u' ! -name 'p' ! -name '*.ext' -delete
find . -type d ! -name 'u' ! -name 'p' ! -name '*.ext' -delete

w celu usunięcia wszystkich plików, w tym katalogów, z wyjątkiem plików u, p i .ext.

Renzo Fabián
źródło
0

Prosty sposób, który trudno zepsuć: powiedzmy, że chcesz usunąć wszystko oprócz * .pdf:

mkdir tmp
mv *.pdf tmp
rm *
mv tmp/* .
rm -r tmp
talloaktrees
źródło