Cómo deshacerse de "No se encontraron coincidencias" cuando se ejecuta "rm *"

22

Utilizando zsh, recibo el mensaje "No se encontró coincidencia" al elegir un patrón que no encaja rmy que incluso al redirigir la salida.

# rm * > /dev/zero 2>&1
  zsh: no matches found: *

¿Cómo puedo deshacerme de este mensaje?

usuario123456
fuente
¿Estás tratando de eliminar todo en el directorio actual? ¿Cuál es el directorio actual?
cutrightjm
Podrías usar setopt extended_glob(o incluso simple rm * >/dev/null 2>&1) pero realmente deberías hacer una solución alternativa para no necesitar rm *, eso es absolutamente peligroso
grochmal
Realmente deberías hundirte en /dev/nulllugar de eso dev/zero. Además, a su redirección stderr le falta un &; debería ser 2>&1.
roaima
El mensaje de error se genera zshdurante la evaluación del comando y no durante el tiempo de ejecución del comando en sí (debido al error, el comando ni siquiera se ejecuta). Las redirecciones de salida aquí solo afectarían la salida del comando y no el shell en sí.
Adaephon

Respuestas:

42

Este comportamiento es controlado por Zsh nomatch opción . Por defecto, si una línea de comando contiene una expresión global que no coincide con nada, Zsh imprimirá el mensaje de error que está viendo y no ejecutará el comando en absoluto. Puede deshabilitar esto ejecutando

setopt +o nomatch

Luego, las expresiones globales que no coinciden con nada se dejarán tal cual, y recibirá un mensaje de error rm(que puede desactivar usando -f, aunque es una mala idea, ya que forzará las eliminaciones en otras situaciones en las que no querer).

Stephen Kitt
fuente
44
El comportamiento también está controlado por las opciones nullgloby cshnullglob. Si nullglobse establece y no se encuentra ningún archivo coincidente, el patrón se elimina de la lista de argumentos en lugar de generar un error. La configuración cshnullglobtiene un efecto similar a menos que todos los patrones en un comando no coincidan, en cuyo caso se informará un error. Nota: configuración nullglobo cshnullglobanulaciones nomatch. También puede establecer nullgloblos patrones individuales utilizando el calificador pegote N: rm *(N).
Adaephon
nomatches menos que ideal, eso es lo que hacen los proyectiles tipo Bourne. Si el patrón no coincide, se pasa como está a rm(!), Lo que rmgenerará un error, o peor aún, podría eliminar el archivo incorrecto para un patrón como, *.[ch]por ejemplo.
Stéphane Chazelas
9

¿Qué le gustaría que hiciera en su lugar? ¿No se ejecuta rmen absoluto (1)? ¿Ejecutarlo con un *argumento literal como en otros shells tipo Bourne (2)? ¿Ejecutarlo sin ningún argumento (3)?

  1. files=(*(N)); (($#files)) && rm -- $files. O (rm -- *) 2> /dev/nullpero eso también ocultaría errores genuinos por los rmcuales sería una tontería. Podrías descartar el zsherror pero restaurar stderr para el rmcomando aunque con(rm -- * 2>&3 3>&-) 3>&2 2> /dev/null
  2. emulate sh -c 'rm -- *' 2> /dev/null. Luego, como en el shque zshahora se emula para esa única línea de comando, la no coincidencia *se pasa tal cual rmy se rmqueja porque ese *archivo no existe. Suprimimos rm's stderr como lo haría en shsuprimir ese mensaje de error, pero de nuevo, que es una tontería, ya que sería ocultar errores genuinos por rmcontraposición al error incurrido por el mal comportamiento de shpasar un literal *a rm. rm -f '*'sin embargo, no se quejaría de un *archivo no existente , por lo que podría haceremulate sh -c 'rm -f -- *'
  3. rm -- *(N). rmse queja de que cuando no se pasa ningún argumento, aunque, de nuevo, no rm -f: rm -f -- *(N).

En general, rm -fes el comando que desea usar si desea que se eliminen todos los archivos y solo obtiene un error si no se pueden eliminar los archivos o si IOW sigue ahí después de que rmhaya regresado. Por lo general, también desea usar -fen scripts para evitar que se le solicite al usuario en algunas situaciones.

Aquí, llamar rmcuando el globo no coincide está mal. El sh1 comportamiento es incorrecto. Es inofensivo para un patrón como *, pero para uno como *.[ch], pasar *.[ch]como está cuando no coincide podría hacer que el *.[ch]archivo se elimine por error:

$ ls
*.[ch]  foo.txt
$ zsh -c 'rm *.[ch]'
zsh:1: no matches found: *.[ch]
$ ls
*.[ch]  foo.txt
$ sh -c 'rm *.[ch]'
$ ls
foo.txt

En su defecto con un error es lo más sensato que hacer y lo que es zsh(y fish, csh,tcsh , bash -o failgloby la cáscara de Unix original) lo hace.

Y si desea cuidarse de ese caso especial, lo zshhace fácil con su (N)calificador global (para noglob ) como en el caso (1) anterior. fish(al menos en la versión reciente ) lo hace aún más fácil ya que hace un noglob implícito para el setcomando. Entonces, el equivalente allí sería:

set files *
if count $files > /dev/null
  rm -f -- $files
end

Vea Por qué nullglob no es el predeterminado para más detalles.


1 . Estrictamente hablando, es solo shdesde el shell Bourne (desde Unix V7 en 1979); las versiones anteriores de sh(que llamaron /etc/globa comodines sin comillas, de donde proviene el nombre de glob ) se comportaron como csho zsh -o cshnullglob, es decir /etc/glob, abortarían el comando si ninguno de los globs coincidía (y suprimiría los globos no coincidentes si al menos uno de ellos tenía alguna coincidencia). El comportamiento fue roto por el shell Bourne.

Stéphane Chazelas
fuente
Creo que espera recibir el mensaje de error rmy no del shell. Algo así como "rm: no se puede eliminar` * ': No existe tal archivo o directorio ".
Emmanuel
@ Emmanuel, entonces eso es 2: emulate sh -c 'rm -- *'obtener el comportamiento (buggy IMO) del shell Bourne.
Stéphane Chazelas
@Stephane_Chazelas como está escrito, 2 es la respuesta correcta a una pregunta que no hizo :).
Emmanuel
@Emmanuel, los 3 responden la pregunta: cómo deshacerse del error "Sin coincidencia". El código del OP suprime los rmerrores. Eso es algo que haría en otros shells para suprimir el error cuando no hay un archivo coincidente y eso también provoca la supresión de errores rm genuinos. Mi respuesta describe eso y espero que muestre cómo es preferible el comportamiento zsh.
Stéphane Chazelas