GOOGLE ADS

Dienstag, 3. Mai 2022

POSIX-Shell (sh) leitet stderr nach stdout um und erfasst stderr und stdout in Variablen

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/4existiert 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 ashund 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_prefixetwas 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

Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...