Come fa un programma a decidere se avere o meno un output colorato?


17

Quando eseguo un comando da un terminale che stampa un output colorato (come lso gcc), viene stampato l'output colorato. Da quanto ho capito, il processo sta effettivamente producendo codici di escape ANSI e il terminale formatta il colore.

Tuttavia, se eseguo lo stesso comando da un altro processo (ad esempio un'applicazione C personalizzata) e reindirizzo l'output all'output dell'applicazione stessa, questi colori non persistono.

In che modo un programma decide se produrre o meno testo con il formato colore? C'è qualche variabile d'ambiente?

Risposte:


25

La maggior parte di questi programmi emette codici colore solo su un terminale per impostazione predefinita; controllano per vedere se il loro output è un TTY, usando isatty(3). Di solito ci sono opzioni per ignorare questo comportamento: disabilitare i colori in tutti i casi o abilitare i colori in tutti i casi. Per GNU, grepad esempio, --color=neverdisabilita i colori e --color=alwaysli abilita.

In una shell è possibile eseguire lo stesso test utilizzando l' -t testoperatore: [ -t 1 ]avrà esito positivo solo se l'output standard è un terminale.


C'è un modo per ingannare l'applicazione avviata che il processo è un tty?
Chris Smith,

4
Chiesto e risposto a unix.stackexchange.com/questions/249723 già, chris13523. A proposito, i commenti non sono davvero il luogo per domande successive.
JdeBP,

1
@ chris13524 vedi il link di JdeBP; puoi anche forzare i programmi a generare codici colore in molti casi (vedi la mia risposta aggiornata).
Stephen Kitt,

13

C'è qualche variabile d'ambiente?

Sì. È la TERMvariabile d'ambiente. Questo perché ci sono diverse cose che vengono utilizzate come parte del processo decisionale.

È difficile generalizzare qui, perché non tutti i programmi concordano su un singolo diagramma di flusso decisionale. In effetti GNU grep, menzionato nella risposta di M. Kitt, è un buon esempio di valore anomalo che utilizza un processo decisionale alquanto insolito con esiti inaspettati. In termini molto generali, quindi:

  • L'output standard deve essere un dispositivo terminale, come determinato da isatty().
  • Il programma deve essere in grado di cercare il record per il tipo di terminale nel database termcap / terminfo.
  • Così dunque ci deve essere un tipo di terminale a guardare in alto. La TERMvariabile di ambiente deve esistere e il suo valore deve corrispondere a un record del database.
  • È pertanto necessario un database terminfo / termcap. Su alcune implementazioni del sottosistema, è possibile specificare l'ubicazione del database termcap utilizzando una TERMCAPvariabile di ambiente. Quindi su alcune implementazioni c'è una seconda variabile d'ambiente.
  • Il record termcap / terminfo deve indicare che il tipo di terminale supporta i colori. C'è un max_colorscampo in terminfo. Non è impostato per tipi di terminali che non dispongono effettivamente di funzionalità di colore. In effetti, esiste una convenzione terminfo secondo cui per ogni tipo di terminale colorabile esiste un altro record con -mo -monoaggiunto al nome che non indica alcuna capacità di colore.
  • Il record termcap / terminfo deve consentire al programma di cambiare colore. Ci sono set_a_foregrounde set_a_backgroundcampi in terminfo.

È un po 'più complesso del semplice controllo isatty(). È reso ulteriormente complicato da diverse cose:

  • Alcune applicazioni aggiungono opzioni della riga di comando o flag di configurazione che sovrascrivono il isatty()controllo, in modo che il programma sia sempre o mai presupponga avere un terminale (colorabile) come output. Per esempio:
    • GNU lsha il--color opzione da riga di comando.
    • BSD lsesamina le variabili di ambiente CLICOLOR(il suo significato in assenza mai ) e CLICOLOR_FORCE(il suo significato in presenza sempre ) e sfoggia anche l' -Gopzione da riga di comando.
  • Alcune applicazioni non usano termcap / terminfo e hanno risposte cablate al valore di TERM.
  • Non tutti i terminali usano sequenze SGR ECMA-48 o ISO 8613-6, che sono leggermente erroneamente denominate "sequenze di fuga ANSI", per cambiare i colori. Il meccanismo termcap / terminfo è infatti progettato per isolare le applicazioni dalla conoscenza diretta delle esatte sequenze di controllo. (Inoltre, c'è da argomentare che nessuno usa sequenze SGR ISO 8613-6, perché tutti concordano sul bug dell'uso di punti e virgola come delimitatore per sequenze SGR di colori RGB. Lo standard specifica in realtà i due punti.)

Come accennato, GNU in greprealtà mostra alcune di queste complessità aggiuntive. Non consulta termcap / terminfo, fissa le sequenze di controllo da emettere e fissa una risposta alla TERMvariabile d'ambiente.

La porta Linux / Unix ha questo codice , che abilita la colorazione solo quando TERMesiste la variabile d'ambiente e il suo valore non corrisponde al nome cablatodumb :

int
should_colorize (vuoto)
{
  char const * t = getenv ("TERM");
  ritorna t && strcmp (t, "dumb")! = 0;
}

Quindi, anche se il vostro TERMIS xterm-mono, GNU grepdeciderà di colori che rilasciano, anche se altri programmi, come vimnon lo faranno.

La porta Win32 ha questo codice , che consente la colorazione sia quando la TERMvariabile di ambiente non esiste o quando esiste e il suo valore non corrisponde al nome cablatodumb :

int
should_colorize (vuoto)
{
  char const * t = getenv ("TERM");
  ritorno ! (t && strcmp (t, "dumb") == 0);
}

grepProblemi di GNU con il colore

grepLa colorazione di GNU è in realtà nota. Poiché in realtà non fa un buon lavoro nella costruzione dell'output del terminale, ma bensì solo in alcune sequenze di controllo cablate in vari punti del suo output nella vana speranza che ciò sia abbastanza buono, in realtà mostra un output errato in determinate circostanze.

Queste circostanze sono dove deve colorare qualcosa che si trova sul margine destro del terminale. I programmi che eseguono correttamente l'output del terminale devono tenere conto dei margini automatici automatici. Oltre alla leggera possibilità che il terminale non possa averli (vale a dire il auto_right_margincampo in terminfo), il comportamento dei terminali che hanno margini a destra automatici spesso segue il precedente DEC VT dell'involucro di linea in sospeso . GNU grepnon tiene conto di questo, ingenuamente si aspetta un avvolgimento di riga immediato e il suo output colorato va storto.

L'output a colori non è una cosa semplice.

Ulteriori letture


2
A quanto ho capito, l'OP sta chiedendo il cambiamento nel comportamento quando l'output viene reindirizzato; $TERMnon lo spiega. (La tua risposta è interessante in generale, ma non credo che affronti la domanda ...)
Stephen Kitt,

molto interessante. Ho desiderato una panoramica come questa su come i programmi scoprono (o semplicemente "decidano") quali sono le funzionalità di un terminale da qualche mese. Questo dà anche un'idea del perché è così difficile trovare una panoramica come questa - perché ogni programma sembra farlo in modo leggermente diverso.
the_velour_fog

Una spiegazione di cosa significano il ritorno a capo in sospeso e il ritorno a capo immediato insieme a un esempio che dimostri la differenza sarebbe utile.
mosvy,

0

Il unbuffercomando dal pacchetto prevede disaccoppia l'output dal primo programma e l'input al secondo programma.

Lo useresti così:

unbuffer myshellscript.sh | grep value

Lo uso sempre con ansible e uno script ctee homebrewed in modo da poter vedere l'output a colori sul terminale, lasciando il file di registro con output normale (non colorato).

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.