Elimine todos los tipos de archivo menos uno (o más)

20

He estado tratando de encontrar un comando para eliminar todos los archivos de una carpeta pero no un tipo de archivo. Pero parece que no tengo suerte. Lo que he probado hasta ahora:

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

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

La versión de zsh que estoy usando es zsh 5.0.2 (x86_64-apple-darwin13.0.1).

Dzung Nguyen
fuente

Respuestas:

22

La extended_globopción le brinda la sintaxis extendida de glob de zsh .

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

Puede configurar la ksh_globopción para obtener ksh globs . Tenga en cuenta que en el caso común donde el patrón negativo es lo último en la palabra, zsh puede analizar los paréntesis como calificadores globales (no lo hace en modo de emulación ksh).

setopt ksh_glob
rm -- !(*.dmg|*.txt)
setopt no_bare_glob_qual
rm -- !(*.dmg)
Gilles 'SO- deja de ser malvado'
fuente
Esto no parece funcionar. Cuando corro rm -r secrets/!(directory), sigue preguntando number expectedo, a veces, me daevent not found: directory
CMCDragonkai
@CMCDragonkai "número esperado" indica que no configuró la ksh_globopción. "Evento no encontrado: directorio" indica que está ejecutando bash (que también comprende la !(…)sintaxis, pero solo después shopt -s extglob).
Gilles 'SO- deja de ser malvado'
¿Cómo podría ejecutar bash cuando estaba en mi shell zsh?
CMCDragonkai
Para mí, setopt ksh_glob; echo !(a|b)funciona mientras setopt ksh_glob; echo !(a)no ("número esperado") ...
ThiefMaster
@ ThhiefMaster Tuve el mismo problema. ¿Es un error?
CodeTower
5

Puede usar en findlugar de su shell:

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

De 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.

Si no puede usarlo findpor alguna razón, aquí hay una manera de hacerlo zsh(u otros shells). zshsiendo zsh, es probable que haya una manera más sencilla de hacer esto, pero ya que soy un bashchico, esto es lo que ocurrió:

for file in *; do if [[ ! "$file" == *.dmg ]]; then rm $file; fi; done
terdon
fuente
desafortunadamente, cada vez que uso find en mi mac, simplemente sale de la sesión actual de zsh sin previo aviso. Tienes el mismo problema ? find [Process completed]
Dzung Nguyen
1
@nXqd ver respuesta actualizada para una forma de hacerlo sin find. Sin findembargo, le sugiero que publique una pregunta sobre su problema, eso no debería suceder. Si lo hace, incluya la salida de type -a find.
terdon
1
Incluso en bash, hay una solución más simple: rm !(*.dmg)después shopt -s extglob.
Gilles 'SO- deja de ser malvado'
@terdon gracias por tus consejos de depuración en shell. su salida parece ser correcta:find is a shell function find is /usr/bin/find
Dzung Nguyen
@nXqd que no es correcto, no debería ser una función de shell, solo debería serlo /usr/bin/find. Tiene una función llamada finddefinida en uno de sus archivos de configuración bash. Ya que estás en OSX, eso es probablemente ~/.profile.
terdon
3

Otra forma de eliminar archivos es con find, xargsy rm:

find . -mindepth 1 -maxdepth 1 ! -name '*.dmg' -print0 | xargs -0 rm
Dragos Rizescu
fuente