Usuń wszystkie typy plików oprócz jednego (lub więcej)

20

Próbowałem znaleźć polecenie usunięcia wszystkich plików w folderze, ale nie rodzaj pliku. Ale chyba nie mam szczęścia. Co próbowałem do tej pory:

set extended_glob
rm !(*.dmg)
# this returns zsh:number expected

rm ./^*.dmg
# this returns no matches found 

Używam wersji zsh zsh 5.0.2 (x86_64-apple-darwin13.0.1).

Dzung Nguyen
źródło

Odpowiedzi:

22

Ta extended_globopcja daje własną rozszerzoną globalną składnię zsh .

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

Możesz ustawić ksh_globopcję pobierania globów ksh . Uwaga: w powszechnym przypadku, gdy wzorzec negatywny jest ostatnią rzeczą w słowie, zsh może analizować nawiasy jako kwalifikatory glob (nie robi tego w trybie emulacji ksh).

setopt ksh_glob
rm -- !(*.dmg|*.txt)
setopt no_bare_glob_qual
rm -- !(*.dmg)
Gilles „SO- przestań być zły”
źródło
To nie działa. Kiedy uruchamiam rm -r secrets/!(directory), ciągle pyta, number expecteda czasem mi to dajeevent not found: directory
CMCDragonkai
@CMCDragonkai „liczba oczekiwana” oznacza, że ​​nie ustawiłeś tej ksh_globopcji. „Event not found: directory” wskazuje, że korzystasz z basha (który również rozumie !(…)składnię, ale dopiero po shopt -s extglob).
Gilles „SO- przestań być zły”
Jak mogłem uruchamiać bash, gdy byłem w mojej powłoce zsh?
CMCDragonkai
Dla mnie setopt ksh_glob; echo !(a|b)działa, podczas gdy setopt ksh_glob; echo !(a)nie działa („liczba oczekiwana”) ...
ThiefMaster
@ ThiefMaster Miałem ten sam problem. Czy to błąd?
CodeTower
5

findZamiast powłoki możesz użyć :

find . -mindepth 1 -maxdepth 1 ! -name "*.dmg" -delete

Od man find:

   ! expr True  if  expr  is false.  This character will also usually need
          protection from interpretation by the shell.
   -name pattern
          Base of file name (the path with the leading directories removed)
          matches shell pattern pattern. 
   -delete
          Delete  files; true if removal succeeded.  If the removal failed,
          an error message is issued.  If -delete fails, find's exit status
          will be nonzero (when  it eventually exits).  Use of -delete 
          automatically turns on the -depth option.

Jeśli nie możesz użyć findz jakiegokolwiek powodu, oto sposób na zrobienie tego za pomocą zsh(lub innych powłok). zshbędąc zsh, istnieje prawdopodobnie prostszy sposób na zrobienie tego, ale ponieważ jestem bashfacetem, oto co wymyśliłem:

for file in *; do if [[ ! "$file" == *.dmg ]]; then rm $file; fi; done
terdon
źródło
niestety, ilekroć używam find w moim Macu, po prostu kończy bieżącą sesję zsh bez żadnego powiadomienia. Czy masz ten sam problem? find [Process completed]
Dzung Nguyen
1
@nXqd zobacz zaktualizowaną odpowiedź na sposób na zrobienie tego bez find. Sugeruję jednak, abyś zadał pytanie dotyczące swojego findproblemu, które nie powinno się zdarzyć. Jeśli tak, dołącz wynik type -a find.
terdon
1
Nawet w bash istnieje prostsze rozwiązanie: rm !(*.dmg)po shopt -s extglob.
Gilles 'SO - przestań być zły'
@terdon dzięki za wskazówki dotyczące debugowania w powłoce. wydaje się, że jego wyniki są poprawne:find is a shell function find is /usr/bin/find
Dzung Nguyen
@ nXqd, który nie jest poprawny, nie powinien być funkcją powłoki, powinien być /usr/bin/find. Masz funkcję o nazwie findzdefiniowaną w jednym z plików konfiguracyjnych bash. Skoro jesteś na OSX, to prawdopodobnie ~/.profile.
terdon
3

Innym sposobem jest usunięcie z plików find, xargsa rm:

find . -mindepth 1 -maxdepth 1 ! -name '*.dmg' -print0 | xargs -0 rm
Dragos Rizescu
źródło