¿Cómo suprimir mensajes de error en zsh?

¿Cómo suprimir mensajes de error en zsh?

en zsh

  • rm foo.barimpresiones rm: foo.bar: No such file or directory.
  • rm foo.bar 2>/dev/nullno imprime nada, como esperaba.

Pero si el comando contiene coincidencias de patrones, el error no se suprime mediante 2>/dev/null:

  • rm *.barimpresiones zsh: no matches found: *.bar.
  • rm *.bar 2>/dev/nullimprime lo mismo.

¿Existe una forma general de suprimir los mensajes de error en zsh? Unosimplemétodo para todo tipo de mensajes de error.

Respuesta1

Cuando intentas ejecutar rm *.bary no hay ningún archivo que coincida *.bar, básicamente pueden pasar dos cosas:

  • El comportamiento POSIX es que el shell se ejecuta rmcon literal *.barcomo argumento. La herramienta intenta eliminar un archivo llamado literalmente *.bar(como si ejecutara rm '*.bar'), falla e imprime algo como rm: *.bar: No such file or directory. Así es como shse comportan el shell POSIX ( ) y los shells compatibles.

  • El comportamiento que no es POSIX es que el shell detecta que no hay coincidencia, imprime algo así como no matches found: *.bary no se ejecutarm en absoluto. Así es como se comporta Zsh por defecto. (A modo de comparación: en Bash puedes cambiar a este comportamiento mediante shopt -s failglob.)

Un error del rm(caso anterior) se imprime en el stderr de rm. Un error del shell (el último caso) se imprime en el stderr del shell.

La redirección rm *.bar 2>/dev/nullafecta al stderr de rmsolo + . En tu ejemplo rmni siquiera se ejecuta.

Para redirigir el stderr del shell principal necesita exec. Por "el shell principal" me refiero al shell interactivo donde escribes; o, en caso de ejecutar un script, el shell que interpreta el script. Ejemplo:

exec 2>/dev/null

En Zsh incluso puedes cerrarlo:

exec 2>&-

Un enfoque razonable es duplicar el stderr original de antemano, en caso de que necesite usarlo (o restaurarlo) más adelante. Ejemplo (tenga en cuenta que si desea pegar este código en un Zsh interactivo, debe invocarsetopt interactive_commentsprimero):

exec 7>&2           # "save" stderr
exec 2>/dev/null    # redirect
rm *.bar
whatever
exec 2>&7           # restore
exec 7>&-           # close descriptor which is no longer needed

Aquí 7hay un número arbitrario de un solo dígito, que de otro modo no se utilizaría como descriptor de archivo. Las dos primeras líneas se pueden escribir como una: exec 7>&2 2>/dev/null; De manera similar, las dos últimas líneas pueden hacerlo.

Tenga en cuenta rmque cualquier comando (como whatever) invocado sin redirección stderr hereda stderr del shell. Esto significa que en el ejemplo anterior rm(si alguna vez se ejecuta) whateverimprimirá sus mensajes de error (si los hay) en /dev/null. Después exec 2>/dev/nullpodrás invocar cualquier número o comando y todos tendrán /dev/nullcomo stderr. Si realmente desea suprimir todo tipo de mensajes de error, esta es la manera.

La solución funciona en muchos shells, no solo en Zsh. Si desea redirigir stderr de un shell interactivo, tenga en cuenta que algunos shells menos sofisticados usan stderr para imprimir su mensaje.

Tenga en cuenta que un proceso puede redirigir su propio stderr (como lo hace nuestro shell con exec 2>…); o puede imprimir mensajes de error en stdout o /dev/tty(no debería, pero técnicamente puede hacerlo). Por lo exec 2>/dev/nulltantonoLe garantizamos que no verá mensajes que parezcan mensajes de error.

Después exec 2>/dev/nullaún puede redirigir stderr de cualquier comando a pedido. Por ejemplo, si en lugar de eso whatevertuviéramos:

whatever 2>&7

entonces sus mensajes de error irían al stderr original que guardamos deliberadamente como descriptor de archivo 7.


execno es la única forma de redirigir stderr (u otro descriptor de archivo) de un shell. Puede tratar un caparazón (aunque no todo el caparazón principal) como lo hace rmen rm … 2>/dev/null. Puedes tratar una subcapa de esta manera:

( rm *.bar ) 2>/dev/null

o simplemente algún código interpretado por el shell principal:

{ rm *.bar; } 2>/dev/null

( ;aquí es opcional en Zsh, obligatorio en algunos otros shells; solo quería que el código funcionara también fuera de Zsh).

Cualquiera de estas líneas puede solucionar tu problema. En el contexto de la supresión de mensajes de error provenientes de un shell, las dos líneas son equivalentes ++ .

Tenga en cuenta que la redirección comienza en (/ {y termina en )/ }, su alcance es limitado. Aún así, puede colocar muchos comandos entre paréntesis, por lo que el alcance "limitado" puede ser en realidad todo el script. O puede ser solo una parte del guión (incluido whateverlo que se presentó anteriormente en esta respuesta, lo que quiera). El hecho de que la redirección deje de funcionar después de )/ }hace que este enfoque sea una excelente alternativa a guardar y restaurar stderr con exec.


+ Estrictamente: afecta " rm" antes y después de convertirse (o intentar convertirse) rm. Tengan paciencia conmigo. La redirección rm … 2>/dev/nullcomienza como una redirección realizada por unshell bifurcado que está a punto de reemplazarse con rmun ejecutable. Este shell redirige su propio stderr antes de intentar reemplazarse con rm. Cualquier error que informe después de realizar la redirección irá a /dev/null. Por ejemplo, si rmno se encuentra, la redirección ya realizada suprimirá el command not founderror.

++ Técnicamente ( … )crea una subcapa, { … }no lo hace. Un subshell se comporta como un proceso de shell separado que hereda las variables y el directorio de trabajo actual, pero no puede cambiar nada (como las variables o el directorio de trabajo actual) en su shell principal. Puede que se realice o no como un proceso verdaderamente separado; lo que importa es el comportamiento. OTOH { … }solo agrupa comandos para algún propósito (en nuestro caso el propósito es la redirección). Esto no significa que nunca haya una subcapa cuando usas { … }; por ejemplo, en una tubería, todas las partes excepto la última son subcapas de todos modos (en algunas capas: todas las partes, incluida la última). Estos detalles técnicos son irrelevantes en el contexto de nuestro problema únicamente, pero en general pueden marcar la diferencia.

información relacionada