Le shell POSIX (sh) redirige stderr vers stdout et capture stderr et stdout dans des variables
Je voudrais rediriger stderr vers stdout afin qu'un terminal les imprime tous les deux lors de l'exécution d'une commande, mais je voudrais également les capturer tous les deux dans des variables distinctes. J'ai réussi à y parvenir dans Bash (version 4.4.20(1)-release):
#!/bin/bash
echo "terminal:"
{ err="$(find / -maxdepth 2 -iname 'tmp' -type d 2>&1 1>&3 3>&- | tee /dev/stderr)"; ec="$?"; } 3>&1 | tee /dev/fd/4 2>&1; out=$(cat /dev/fd/4)
echo "stdout:" && echo "$out"
echo "stderr:" && echo "$err"
cela donne souhaité:
terminal:
find: '/root': Permission denied
/tmp
/var/tmp
find: '/lost+found': Permission denied
stdout:
/tmp
/var/tmp
stderr:
find: '/root': Permission denied
find: '/lost+found': Permission denied
mais j'ai un problème pour convertir ce script en POSIX sh/bin/sh
#!/bin/sh
echo "terminal:"
{ err="$(find / -maxdepth 2 -iname 'tmp' -type d 2>&1 1>&3 3>&- | tee /dev/stderr)"; ec="$?"; } 3>&1 | tee /dev/fd/4 2>&1; out=$(cat /dev/fd/4)
echo "stdout:" && echo "$out"
echo "stderr:" && echo "$err"
donne:
terminal:
tee: /dev/fd/4: No such file or directory
find: '/root': Permission denied
/tmp
/var/tmp
find: '/lost+found': Permission denied
cat: /dev/fd/4: No such file or directory
stdout:
stderr:
/dev/fd/4
n'existe pas, et il n'y a pas /proc/self/fd/4
non plus.
Comment faire en sorte que ce script fonctionne comme un script shell POSIX ?
Solution du problème
Eh bien, je le fais dans le ash
shell de busybox et mes options sont plutôt limitées, mais c'est ce que j'ai trouvé qui fonctionne.
tmpfile=/tmp/some_prefix_stderr.$$
out=$(my_cmd) 2>$tmpfile
result=$?
err=$(cat $tmpfile)
rm $tmpfile
Ce n'est pas le plus beau, mais ça marche. En général, remplacez some_prefix
par quelque chose de spécifique pour éviter les collisions, mais le simple fait d'avoir le PID là-bas résoudra cela à moins que vous n'exécutiez plusieurs threads.
Si vous pouvez vous attendre à ce que votre programme sorte non nul lorsqu'il y a quelque chose à afficher dans stderr, vous pouvez le simplifier un peu:
tmpfile=/tmp/some_prefix_stderr.$$
if! out=$(my_cmd) 2>$tmpfile; then
# specific behavior here
cat $tmpfile >&2
fi
rm $tmpfile
Tout cela est conforme à POSIX. Assurez-vous simplement de nettoyer votre fichier temporaire.
Commentaires
Enregistrer un commentaire