¿Cómo decide un programa si desea o no tener una salida en color?

¿Cómo decide un programa si desea o no tener una salida en color?

Cuando ejecuto un comando desde una terminal que imprime una salida en color (como lso gcc), se imprime la salida en color. Según tengo entendido, el proceso en realidad está generandoCódigos de escape ANSI, y el terminal formatea el color.

Sin embargo, si ejecuto el mismo comando mediante otro proceso (por ejemplo, una aplicación C personalizada) y redirijo la salida a la propia salida de la aplicación, estos colores no persisten.

¿Cómo decide un programa si genera o no texto con formato de color? ¿Existe alguna variable de entorno?

Respuesta1

La mayoría de estos programas sólo envían códigos de color a una terminal de forma predeterminada; verifican si su salida es un TTY, usandoisatty(3). Generalmente existen opciones para anular este comportamiento: deshabilitar colores en todos los casos o habilitar colores en todos los casos. Para GNU, greppor ejemplo, --color=neverdesactiva los colores y --color=alwayslos activa.

En un shell puedes realizar la misma prueba usando el-t testoperador:[ -t 1 ] tendrá éxito sólo si la salida estándar es un terminal.

Respuesta2

¿Existe alguna variable de entorno?

Sí. Es la TERMvariable de entorno. Esto se debe a que hay varias cosas que se utilizan como parte del proceso de decisión.

Es difícil generalizar aquí, porque no todos los programas coinciden en un único diagrama de flujo de decisión. De hecho GNUgrep , mencionado en la respuesta de M. Kitt, es un buen ejemplo de un valor atípico que utiliza un proceso de decisión algo inusual con resultados inesperados. Por lo tanto, en términos muy generales:

  • La salida estándar debe ser un dispositivo terminal, según lo determinado por isatty().
  • El programa debe poder buscar el registro del tipo de terminal en la base de datos termcap/terminfo.
  • Por lo tanto debe haberserun tipo de terminal para buscar. La TERMvariable de entorno debe existir y su valor debe coincidir con un registro de la base de datos.
  • Por lo tanto, debe existir una base de datos terminfo/termcap. En algunas implementaciones del subsistema, la ubicación de la base de datos termcap se puede especificar usando unTERMCAP variable de entorno. Entonces, en algunas implementaciones hay unasegundoVariable ambiental.
  • El registro termcap/terminfo debe indicar que el tipo de terminal admite colores. Hay un max_colorscampo en terminfo. No está configurado para tipos de terminales que en realidad no tienen capacidades de color. De hecho, existe una convención terminfo según la cual para cada tipo de terminal coloreable hay otro registro -madjunto -monoal nombre que indica que no hay capacidad de color.
  • El registro termcap/terminfo debe proporcionar la forma para que el programa cambie de color. Hay campos set_a_foregroundy set_a_backgrounden terminfo.

Es un poco más complejo que simplemente comprobarisatty() . Está hechomáscomplicado por varias cosas:

  • AlgunoLas aplicaciones agregan opciones de línea de comandos o indicadores de configuración que anulan elisatty() verificación, de modo que el programasiempreonuncaasume que tiene un terminal (colorable) como salida. Por ejemplo:
    • GNU lstiene la --coloropción de línea de comandos.
    • BSD lsmira elCLICOLOR (su significado de ausencia)nunca) yCLICOLOR_FORCE (su presencia significasiempre) variables de entorno y también cuenta con la -Gopción de línea de comandos.
  • Algunolas aplicaciones no usan termcap/terminfo y tienen respuestas programadas al valor de TERM.
  • No todos los terminales utilizan secuencias ECMA-48 o ISO 8613-6 SGR, que reciben un ligero nombre incorrecto "secuencias de escape ANSI", para cambiar de color. De hecho, el mecanismo termcap/terminfo está diseñado para aislar las aplicaciones del conocimiento directo de las secuencias de control exactas. (Además, se puede argumentar quenadieutiliza secuencias ISO 8613-6 SGR, porquetodos están de acuerdo en el errorde utilizar punto y coma como delimitador para secuencias SGR de color RGB. El estándar en realidad especifica dos puntos).

Como se mencionó, GNU grepen realidad presenta algunas de estas complejidades adicionales. No consulta termcap/terminfo, cablea las secuencias de control para emitir y cablea una respuesta a la TERMvariable de entorno.

ElEl puerto Linux/Unix tiene este código, que permite la coloración solo cuando la TERMvariable de entorno existe y su valor no coincide con el nombre cableadodumb :

En t
debería_colorizar (nulo)
{
  char const *t = getenv ("TERMINO");
  return t && strcmp (t, "tonto") != 0;
}

Entonces, incluso si lo TERMes xterm-mono, GNU grepdecidirá emitir colores, aunque otros programas como vimno lo harán.

ElEl puerto Win32 tiene este código, que permite la colorización ya sea cuando la TERMvariable de entornono esexiste o cuando existe y su valor no coincide con el nombre cableadodumb :

En t
debería_colorizar (nulo)
{
  char const *t = getenv ("TERMINO");
  devolver ! (t && strcmp (t, "tonto") == 0);
}

Los problemas de GNU grepcon el color

grepLa coloración de GNU es realmente notoria. Debido a que en realidad no hace un trabajo adecuado al construir la salida del terminal, sino que simplemente culpa a algunas secuencias de control cableadas en varios puntos de su salida con la vana esperanza de que sea lo suficientemente buena, en realidad muestra una salida incorrecta en ciertas circunstancias.

En estas circunstancias es donde hay que colorear algo que se encuentra en el margen derecho del terminal. Los programas que realizan salidas de terminal correctamente deben tener en cuenta los márgenes derechos automáticos. Ademása la mínima posibilidad de que el terminal no los tenga (a saber, elauto_right_margin campo en terminfo), el comportamiento de los terminales que sí tienen márgenes derechos automáticos a menudo sigue el precedente DEC VT deajuste de línea pendiente. ÑUgrep no tiene en cuenta esto, esperando ingenuamenteajuste de línea inmediatoy su salida en color sale mal.

La impresión en color no es algo sencillo.

Otras lecturas

Respuesta3

Elunbuffer comando de laesperarEl paquete desacopla la salida del primer programa y la entrada al segundo programa.

Lo usarías así:

unbuffer myshellscript.sh | grep value

Lo uso todo el tiempo con ansible y casero.cteescript para poder ver la salida en color en la terminal, mientras dejo el archivo de registro con una salida normal (sin color).

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log

información relacionada