Bash script – stocke stderr dans une variable

J’écris un script pour sauvegarder une firebase database. J’ai la ligne suivante:

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

Je veux assigner le stderr à une variable, de manière à ce qu’il m’envoie un email pour me faire savoir ce qui s’est passé si quelque chose ne va pas. J’ai trouvé des solutions pour redirect stderr vers stdout, mais je ne peux pas le faire car la sortie standard est déjà envoyée (via gzip) dans un fichier. Comment puis-je stocker stderr séparément dans une variable $ result?

Essayez de redirect stderr vers stdout et utilisez $() pour capturer cela. En d’autres termes:

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

Comme votre commande redirige quelque part la sortie standard, elle ne devrait pas interférer avec stderr. Il pourrait y avoir une façon plus propre de l’écrire, mais cela devrait fonctionner.

Modifier:

Cela fonctionne vraiment. Je l’ai testé:

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

va imprimer BLAH=err et le fichier log contient.

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

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

La sortie normale apparaît normalement, tout ce qui est stderr est capturé dans $ error (citez-le comme “$ error” lorsque vous l’utilisez pour conserver les nouvelles lignes). Pour capturer stdout dans un fichier, ajoutez simplement une redirection à la fin, par exemple:

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

Briser, lire de l’extérieur, ça:

  • crée une description de fichier $ out pour tout le bloc, en dupliquant stdout
  • capture la sortie standard de la commande entière dans $ error (mais voir ci-dessous)
  • la commande redirige stderr vers stdout (qui est capturée ci-dessus) puis stdout vers la sortie standard depuis l’extérieur du bloc, de sorte que seul le stderr soit capturé

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), puis redirect stderr vers celui-ci:

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

Donc, 3>&1 redirecta le fichier numéro 3 vers stdout (notez que c’est avant que stdout ne soit redirigé avec le tube). Ensuite, 2>&3 redirige stderr vers le fichier numéro 3, qui est maintenant identique à stdout. Finalement, stdout est redirigé en étant introduit dans un tube, mais cela n’affecte pas les numéros de fichiers 2 et 3 (notez que la redirection de stdout depuis gzip n’est pas liée aux sorties de la commande mysqldump).

Edit: Mise à jour de la commande pour redirect stderr depuis la commande mysqldump et non pas gzip , j’étais trop rapide dans ma première réponse.

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 stream sont indépendants et redirigeables 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 aviez vraiment besoin d'une variable:

 $ variable=`cat countfile`