Ich versuche, meine stderr
im Terminal rot auszudrucken. Das folgende Skript leitet sie bei Debug 2
zu einem benutzerdefinierten 8
Trap um.
exec 9>&2
exec 8> >(
while IFS='' read -r line || [ -n "$line" ]; do
echo -e "${RED}${line}${COLORRESET}"
done
)
function undirect(){ exec 2>&9; } # reset to original 9 (==2)
function redirect(){ exec 2>&8; } # set to custom 8
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'
Es kommt vonHier, mit einer klaren Erklärung.
Scheint sehr gut zu funktionieren, allerdings werden Eingaben, die nicht durch eine neue Zeile abgeschlossen sind, überhaupt nicht ausgegeben. Zitat des Autorsgospeswieder:
bash> echo -en "hi\n" 1>&2
hi <-- this is red
bash> echo -en "hi" 1>&2
bash> echo -en "hi" 1>&2
bash> echo -en "hi\n" 1>&2
hihihi <-- this is red
Ich kann nicht herausfinden, warum. Der Inhalt ohne Zeilenumbruch scheint in einer Art Puffer zu landen. Entweder erreicht er nicht einmal den Dateideskriptor 8
oder will irgendwie nicht sofort ausgedruckt werden. Wohin geht er? redirect
wird jedes Mal richtig aufgerufen. Außerdem IFS=''
bedeutet es, dass es kein Trennzeichen gibt, also verstehe ich nicht ganz, warum die Ausgabe 8
zeilenweise erfolgt.
Ein Bugfix wäre sehr willkommen, ich habe die zitierte Antwort auf diese Frage verlinkt.
Diese gesamte Lösung ist, wie Gilles anmerkt, nicht ganz perfekt. Ich habe Probleme mit Lesen, Standardeingabe, Fortschrittsbalken, kann weder su
noch source
. Und häufig größere Probleme wie unterbrochene Pipes und unerwartete Terminal-Exits. Wenn jemand über meinen Link hierher gelangt ist, erwäge bitte die Verwendung vonhttps://github.com/sickill/stderredstattdessen ist es viel besser (noch keine Probleme) ( echo bla >&2
bleibt jedoch nicht rot undDas jeweilige Problem ist geschlossen)
Antwort1
Sie haben die Teilzeilenausgabe als Teil derselben Zeile an der Stelle erhalten, an der die neue Zeile gedruckt wurde. Die Teile der Zeile werden innerhalb gepuffert read
.das ist, was es tut:
DerlesenDas Dienstprogramm soll eine einzelne logische Zeile von der Standardeingabe lesen
Dies wird beispielsweise <foobar>
nach einer Sekunde gedruckt, nicht nach <foo><bar>
.
(echo -n foo ; sleep 1 ; echo bar) | (read x ; echo "<$x>")
Wenn Sie Eingaben in kleineren Teilen als ganzen Zeilen erfassen möchten, müssen Sie etwas anderes tun, z. B. mit Perl. Dies würde drucken <foo><bar\n>
(mit dem Zeilenumbruch vor dem letzten >
, da read
Perl im Gegensatz zu den letzten Zeilenumbrüchen nicht speziell behandelt. Sollte bei der Farbgebung keine Rolle spielen.)
(echo -n foo ; sleep 1 ; echo bar) |
perl -e '$|=1; while(sysread STDIN,$a,9999) { print "<$a>"}'
Wenn Sie die Steuercodes für Farben ( RED
und COLORRESET
) in die Umgebung exportiert haben, können Sie sie wie hier aus dem Perl-Skript verwenden:
perl -e '$|=1; while(sysread STDIN,$a,9999) {print "$ENV{RED}$a$ENV{COLORRESET}"}'
Antwort2
In Bash können Sie die -d
Option „Builtin“ verwenden read
, die das Zeilenendesymbol definiert. man bash
gibt Folgendes an:
-d delim The first character of delim is used to terminate the input line,
rather than newline.
Wenn es nicht definiert ist, read
wartet es, bis \n
es erscheint, um einen String als Zeile zu betrachten. Wenn Sie die -d
Option jedoch verwenden, können Sie es NUL
als Trennzeichen festlegen. Natürlich müssen Sie die Eingabe dann auch mit NUL beenden.
Beispiel:
printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
do
printf "%s\n" "$line"
done
Ausgabe:
x
y
z
Nochmal, aber jetzt steht das printf
in der Schleife nicht bei .while
\n
printf "%s\0" $'x\n' y z | while IFS='' read -r -d $'\0' line
do
printf "%s" "$line"
done
Ausgabe:
x
yz(...)
Ich habe das hinzugefügt (...)
und es bedeutet, dass am Ende der zweiten Zeile kein Zeilenende steht. Aber der Text wird trotzdem verarbeitet und gedruckt.