Bash script-stocker stderr dans une variable [dupliquer]

cette question a déjà une réponse ici:

j'écris un script pour sauvegarder une base de données. J'ai la ligne suivante:

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

je veux assigner le stderr à un variable, de sorte qu'il va envoyer un email à moi-même me faire savoir ce qui s'est passé si quelque chose va mal. J'ai trouvé des solutions pour rediriger stderr vers stdout, mais je ne peux pas le faire car stdout est déjà envoyé (via gzip) vers un fichier. Comment puis-je stocker séparément stderr dans une variable $result ?

39
demandé sur codeforester 2010-06-28 10:06:54

4 réponses

essayez de rediriger stderr vers stdout et utilisez $() pour capturer cela. En d'autres termes:

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

puisque votre commande redirige stdout quelque part, elle ne devrait pas interférer avec stderr. Il pourrait y avoir une manière plus propre de l'écrire, mais cela devrait fonctionner.

Edit:

ça marche vraiment. Je l'ai testé:

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

echo "BLAH=$BLAH"

imprime BLAH=err et le le fichier log contient out .

68
répondu Adam Crume 2010-06-28 06:29:45

pour toute commande générique en Bash, vous pouvez faire quelque chose comme ceci:

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

sortie régulière apparaît normalement, tout à stderr est capturé dans $error (citez-le comme "$error" en l'utilisant pour préserver newlines). Pour capturer stdout dans un fichier, il suffit d'ajouter une redirection à la fin, par exemple:

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

en décomposant, à la lecture de l'extérieur, c':

  • crée une description de fichier $out pour l'ensemble du bloc, dupliquer stdout
  • capture le stdout de toute la commande en $ error (mais voir ci-dessous)
  • la commande elle-même redirige stderr vers stdout (qui est capturé ci-dessus) puis stdout vers le stdout original depuis l'extérieur du bloc, donc seul le stderr est capturé
13
répondu Joat 2011-06-12 00:44:58

vous pouvez enregistrer la référence stdout avant qu'elle ne soit redirigée dans un autre numéro de fichier (par exemple 3) et ensuite rediriger stderr à cela:

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

donc 3>&1 redirigera le fichier Numéro 3 vers stdout (notez que c'est avant que stdout soit redirigé avec le tuyau). Puis 2>&3 redirige stderr vers le fichier numéro 3, qui est maintenant le même que stdout. Enfin stdout est redirigé en étant introduit dans un tuyau, mais cela n'affecte pas les numéros de fichiers 2 et 3 (avis que la redirection de stdout à partir de gzip n'est pas liée aux sorties de la commande mysqldump).

Edit: mise à jour de la commande pour rediriger stderr de la commande mysqldump et non gzip , j'ai été trop rapide dans ma première réponse.

4
répondu hlovdal 2010-06-28 06:58:40

dd écrit à la fois stdout et stderr:

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

les deux flux sont indépendants et peuvent être redirigés séparément:

$ 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 vous avez vraiment besoin d'une variable:

$ variable=`cat countfile`
0
répondu msw 2010-06-28 06:22:07