Ich möchte stderr nach stdout umleiten, damit ein Terminal beide während einer Befehlsausführung druckt, aber ich möchte auch beide in separaten Variablen erfassen. Das ist mir in Bash (Version 4.4.20(1)-Release) gelungen:
#!/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"
das gibt erwünscht:
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
aber ich habe ein Problem beim Konvertieren dieses Skripts in 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"
gibt:
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
existiert nicht, und es gibt auch keine /proc/self/fd/4
.
Wie lässt sich dieses Skript als POSIX-Shell-Skript verwenden?
Lösung des Problems
Nun, ich mache das in der Shell von busybox ash
und meine Optionen sind ziemlich begrenzt, aber das ist, was ich mir ausgedacht habe, das funktioniert.
tmpfile=/tmp/some_prefix_stderr.$$
out=$(my_cmd) 2>$tmpfile
result=$?
err=$(cat $tmpfile)
rm $tmpfile
Es ist nicht das schönste, aber es funktioniert. Ersetzen Sie im Allgemeinen durch some_prefix
etwas Bestimmtes, um Kollisionen zu vermeiden, aber wenn Sie nur die PID dort haben, wird das gelöst, es sei denn, Sie führen mehrere Threads aus.
Wenn Sie sich darauf verlassen können, dass Ihr Programm nicht Null verlässt, wenn es etwas in stderr anzuzeigen gibt, können Sie es ein wenig vereinfachen:
tmpfile=/tmp/some_prefix_stderr.$$
if! out=$(my_cmd) 2>$tmpfile; then
# specific behavior here
cat $tmpfile >&2
fi
rm $tmpfile
Dies ist alles POSIX-konform. Stellen Sie einfach sicher, dass Sie Ihre temporäre Datei bereinigen.
Keine Kommentare:
Kommentar veröffentlichen