
Wenn ich einen Befehl von einem Terminal aus ausführe, der farbige Ausgaben druckt (wie ls
odergcc
), wird die farbige Ausgabe gedruckt. Nach meinem Verständnis gibt der Prozess tatsächlich ausANSI-Escape-Codes, und das Terminal formatiert die Farbe.
Wenn ich jedoch denselben Befehl durch einen anderen Prozess (z. B. eine benutzerdefinierte C-Anwendung) ausführe und die Ausgabe auf die Ausgabe der Anwendung umleite, bleiben diese Farben nicht bestehen.
Wie entscheidet ein Programm, ob Text im Farbformat ausgegeben wird oder nicht? Gibt es dafür Umgebungsvariable?
Antwort1
Die meisten dieser Programme geben standardmäßig nur Farbcodes an ein Terminal aus. Sie prüfen, ob ihre Ausgabe ein TTY ist, indem sieisatty(3)
. Normalerweise gibt es Optionen, um dieses Verhalten zu überschreiben: Farben in allen Fällen deaktivieren oder Farben in allen Fällen aktivieren. Für GNU werden grep
beispielsweise --color=never
Farben deaktiviert und --color=always
aktiviert.
In einer Shell können Sie den gleichen Test durchführen mit dem-t
test
Operator: [ -t 1 ]
ist nur erfolgreich, wenn die Standardausgabe ein Terminal ist.
Antwort2
Gibt es eine Umgebungsvariable?
Ja. Es ist die TERM
Umgebungsvariable. Dies liegt daran, dass im Entscheidungsprozess mehrere Dinge verwendet werden.
Es ist schwierig, hier zu verallgemeinern, da nicht alle Programme einem einzigen Entscheidungsflussdiagramm zustimmen. Tatsächlich grep
ist GNU , das in M. Kitts Antwort erwähnt wird, ein gutes Beispiel für einen Ausreißer, der einen etwas ungewöhnlichen Entscheidungsprozess mit unerwarteten Ergebnissen verwendet. Ganz allgemein ausgedrückt gilt daher:
- Die Standardausgabe muss ein Terminalgerät sein, wie von bestimmt
isatty()
. - Das Programm muss in der Lage sein, den Datensatz für den Terminaltyp in der Termcap/Terminfo-Datenbank nachzuschlagen.
- Deshalb muss esSeiein nachzuschlagender Terminaltyp. Die
TERM
Umgebungsvariable muss vorhanden sein und ihr Wert muss mit einem Datenbankeintrag übereinstimmen. - Es muss daher eine terminfo/termcap-Datenbank geben. Bei einigen Implementierungen des Subsystems kann der Speicherort der termcap-Datenbank mithilfe einer
TERMCAP
Umgebungsvariable angegeben werden. Bei einigen Implementierungen gibt es also einezweiteUmgebungsvariable. - Der Termcap/Terminfo-Eintrag muss angeben, dass der Terminaltyp Farben unterstützt.
max_colors
In Terminfo gibt es ein Feld. Es ist nicht für Terminaltypen festgelegt, die eigentlich keine Farbfähigkeiten haben. Tatsächlich gibt es eine Terminfo-Konvention, dass es für jeden farbfähigen Terminaltyp einen anderen Eintrag mit-m
oder-mono
an den Namen angehängt gibt, der keine Farbfähigkeit angibt. - Der Termcap/Terminfo-Datensatz muss dem Programm die Möglichkeit bieten, Farben zu ändern. In Terminfo gibt es
set_a_foreground
und -Felder.set_a_background
Es ist etwas komplexer als nur zu prüfenisatty()
. Es bestehtweiterdurch mehrere Dinge kompliziert:
- MancheAnwendungen fügen Befehlszeilenoptionen oder Konfigurationsflags hinzu, die die
isatty()
Prüfung außer Kraft setzen, so dass das Programmstetsoderniemalssetzt voraus, dass es ein (färbbares) Terminal als Ausgabe hat. Beispiele:- GNU
ls
verfügt über eine--color
Befehlszeilenoption. - BSD
ls
betrachtet dieCLICOLOR
(ihre Abwesenheit Bedeutungniemals) UndCLICOLOR_FORCE
(seine Anwesenheit bedeutetstets) Umgebungsvariablen und bietet auch die-G
Befehlszeilenoption.
- GNU
- MancheAnwendungen verwenden kein Termcap/Terminfo und haben fest verdrahtete Reaktionen auf den Wert von
TERM
. - Nicht alle Terminals verwenden ECMA-48- oder ISO 8613-6-SGR-Sequenzen, die leicht fälschlicherweise „ANSI-Escape-Sequenzen“ genannt werden, um Farben zu ändern. Der Termcap/Terminfo-Mechanismus ist tatsächlich so konzipiert, dass er Anwendungen vor der direkten Kenntnis der genauen Steuersequenzen schützt. (Darüber hinaus gibt es ein Argument, dassniemandverwendet ISO 8613-6 SGR-Sequenzen, weilalle sind sich über den Fehler einigder Verwendung eines Semikolons als Trennzeichen für RGB-Farb-SGR-Sequenzen. Der Standard gibt eigentlich einen Doppelpunkt vor.)
Wie erwähnt grep
weist GNU tatsächlich einige dieser zusätzlichen Komplexitäten auf. Es konsultiert nicht termcap/terminfo, verdrahtet die auszugebenden Steuersequenzen fest und verdrahtet eine Antwort auf die TERM
Umgebungsvariable.
DerDer Linux/Unix-Port davon hat diesen Code, das die Farbgebung nur aktiviert, wenn die TERM
Umgebungsvariable vorhanden ist und ihr Wert nicht mit dem fest verdrahteten Namen übereinstimmt dumb
:
int sollte_einfärben (ungültig) { char const *t = getenv ("TERM"); return t und strcmp (t, "dumm") != 0; }
Auch wenn Ihr also TERM
ist xterm-mono
, wird GNU grep
entscheiden, Farben auszugeben, obwohl andere Programme wie vim
dies nicht tun.
DerDer Win32-Port davon hat diesen Code, wodurch die Farbgebung entweder dann aktiviert wird, wenn die TERM
Umgebungsvariablenichtexistiert oder wenn es existiert und sein Wert nicht mit dem fest verdrahteten Namen übereinstimmt dumb
:
int sollte_einfärben (ungültig) { char const *t = getenv ("TERM"); Rückgabe ! (t und strcmp (t, "dumm") == 0); }
GNUs grep
Probleme mit Farbe
Die Farbgebung von GNU grep
ist tatsächlich berüchtigt. Da es die Terminalausgabe nicht richtig erstellt, sondern einfach an verschiedenen Stellen in seiner Ausgabe ein paar fest verdrahtete Steuersequenzen einfügt, in der vergeblichen Hoffnung, dass das gut genug ist, zeigt es unter bestimmten Umständen tatsächlich eine falsche Ausgabe an.
Unter diesen Umständen muss etwas am rechten Rand des Terminals eingefärbt werden. Programme, die die Terminalausgabe ordnungsgemäß ausführen, müssen automatische rechte Ränder berücksichtigen. Zusätzlichbis hin zur geringen Möglichkeit, dass das Terminal sie nicht hat (nämlich dieauto_right_margin
Feld in terminfo), folgt das Verhalten von Terminals, die automatische rechte Ränder haben, oft dem DEC VT-Präzedenzfall vonausstehender Zeilenumbruch. GNUgrep
berücksichtigt dies nicht und erwartet naivsofortiger Zeilenumbruch, und die farbige Ausgabe geht schief.
Farbige Ausgabe ist keine einfache Sache.
Weiterführende Literatur
- Thomas E. Dickey (2016). "
grep --color
zeigt nicht die richtige Ausgabe".Häufig gestellte Fragen zu xterm. Unsichtbare Insel. - Jonathan de Boyne Pollard (2016).Kursivschrift und Farbe in Handbuchseiten auf einem virtuellen Nosh-Benutzerterminal. Das Nosh-Paket.
Antwort3
Derunbuffer
Befehl aus demerwartenPaket entkoppelt die Ausgabe des ersten Programms und die Eingabe des zweiten Programms.
Sie würden es folgendermaßen verwenden:
unbuffer myshellscript.sh | grep value
Ich benutze es ständig mit Ansible und einem HomebrewedcteeSkript, damit ich die Farbausgabe auf dem Terminal sehen kann, während die Protokolldatei die normale (nicht farbige) Ausgabe behält.
unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log