2010-06-28 21 views
34

Estoy escribiendo una secuencia de comandos para hacer una copia de seguridad de una base de datos. Tengo la línea siguiente:Script Bash - almacenar stderr en una variable

mysqldump --user=$dbuser --password=$dbpswd \ 
    --host=$host $mysqldb | gzip > $filename 

que desea asignar el stderr a una variable, por lo que va a enviar un correo electrónico a mí mismo que me deja saber lo que pasó si algo va mal. He encontrado soluciones para redirigir stderr a stdout, pero no puedo hacer eso ya que el stdout ya se está enviando (a través de gzip) a un archivo. ¿Cómo puedo almacenar Stderr por separado en un $ resultado variable?

Respuesta

57

Try redirigir stderr a stdout y utilizando $() para capturar eso. En otras palabras:

VAR=$((your-command-including-redirect) 2>&1) 

Dado que su comando redirige a stdout a algún lugar, no debe interferir con stderr. Puede haber una manera más limpia de escribirlo, pero eso debería funcionar.

Editar:

Este trabajo realmente tiene. Lo he probado:

#!/bin/bash                                           
BLAH=$((
(
echo out >&1 
echo err >&2 
) 1>log 
) 2>&1) 

echo "BLAH=$BLAH" 

imprimirá BLAH=err y el archivo contiene logout.

+0

No creo que esto funcione. stderr se redirige a stdout, que luego se redirige a un archivo. No puede redireccionar la salida estándar del comando a un archivo y luego reemplazar la salida estándar mostrada con stderr –

+0

@Michael: vea mi edición. –

+0

Funciona a la perfección. ¡Gracias! – thornate

0

dd escribe stdout y stderr:

$ dd if=/dev/zero count=50 > /dev/null 
50+0 records in 
50+0 records out 

las dos corrientes son independientes y por separado redirectable:

$ dd if=/dev/zero count=50 2> countfile | wc -c 
25600 
$ cat countfile 
50+0 records in 
50+0 records out 
$ mail -s "countfile for you" thornate < countfile 

si realmente se necesita una variable:

$ variable=`cat countfile` 
4

Puede guarde la referencia de stdout antes de que se redirija en otra f número de ile (por ej. 3) y luego redirigir stderr a que:

result=$(mysqldump --user=$dbuser --password=$dbpswd \ 
    --host=$host $mysqldb 3>&1 2>&3 | gzip > $filename) 

Así 3>&1 se redirigir número de expediente 3 a la salida estándar (nótese esto es antes de la salida estándar es redirigido con el tubo). Luego, 2>&3 redirige stderr al archivo número 3, que ahora es el mismo que stdout. Finalmente, stdout se redirige al alimentarlo a un conducto, pero esto no afecta a los números de archivo 2 y 3 (observe que redireccionar el stdout de gzip no está relacionado con las salidas del comando mysqldump).

Editar: Actualizado el comando para redirigir stderr del comando mysqldump y no gzip, fui demasiado rápido en mi primera respuesta.

8

Para cualquier comando genérico en Bash, se puede hacer algo como esto:

{ error=$(command 2>&1 1>&$out); } {out}>&1 

de salida regular aparece normalmente, nada en stderr es capturado en $ error (cita como "$ error" cuando lo utilice para preservar nuevas líneas).Para capturar la salida estándar a un archivo, basta con añadir una redirección al final, por ejemplo:

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output 

Descomponiéndola, la lectura de afuera hacia adentro, es:

  • crea una descripción del archivo $ por todo el bloque, la duplicación de la salida estándar
  • captura la salida estándar de todo el comando en $ error (pero véase más adelante)
  • el propio comando redirige stderr a stdout (que es capturado por encima), entonces la salida estándar a la salida estándar originales desde fuera del bloque , entonces solo el stderr se vuelve captu rojo
+1

No funciona en bash v3.2: '' token inesperado '{out} '' '. ¿Requiere esta sintaxis Bash 4? –

+0

funcionó bien en bash 4.2, y 4.1, incluso probé los shopts: compat32, compat31, y funcionó muy bien también, tal vez es un error en 3.2 ya que cuando bash está en modo de compatibilidad funciona, a menos que la compatibilidad solo abarque elementos eso no se rompería debido a 4.2, no las características que serían parte de 4.2 ... (creo que la mayoría de la gente usa 4.2 en estos días, ¿no es así?) De todos modos, esta es una publicación anterior, pero solo para borrarla, funciona y era justo lo que necesitaba para asignar errores a las variables mientras mostraba el texto normal en la pantalla ... :) – osirisgothra

Cuestiones relacionadas