Як програма вирішує, мати кольоровий вихід чи ні?


17

Коли я виконую команду з терміналу, який друкує кольоровий вихід (наприклад, lsабо gcc), кольоровий вихід надрукується . З мого розуміння, процес насправді виводить ANSI коди виходу , а термінал формує колір.

Однак якщо я виконую ту саму команду іншим процесом (скажімо, власною програмою C) і перенаправляю висновок на власний вихід програми, ці кольори не зберігаються.

Як програма вирішує, виводити текст чи кольоровий формат чи ні? Чи є якась змінна середовище?

Відповіді:


25

Більшість таких програм за замовчуванням виводять лише кольорові коди до терміналу; вони перевіряють, чи є їх вихід TTY, використовуючи isatty(3). Зазвичай існують варіанти, щоб змінити таку поведінку: вимкнути кольори у всіх випадках або включити кольори у всіх випадках. Наприклад, grepдля GNU --color=neverвимикає кольори та --color=alwaysвмикає їх.

У оболонці ви можете виконати той же тест, використовуючи -t test оператора: [ -t 1 ]буде успішним лише в тому випадку, якщо стандартним висновком є ​​термінал.


Чи є якийсь спосіб обмацувати запущене додаток, що процес є тти?
Кріс Сміт

4
На запитання та відповіді на unix.stackexchange.com/questions/249723 вже, chris13523. До речі, коментарі насправді не місце для наступних питань.
JdeBP

1
@ chris13524 див. посилання JdeBP; Ви також можете змусити програми виводити кольорові коди у багатьох випадках (див. мою оновлену відповідь).
Стівен Кітт

13

Чи є якась змінна середовище?

Так. Це TERMзмінна середовище. Це тому, що є кілька речей, які використовуються як частина процесу прийняття рішення.

Тут важко узагальнити, оскільки не всі програми узгоджуються на єдиній блок-схемі прийняття рішень. Насправді, GNU grep, згаданий у відповіді М. Кітта, є хорошим прикладом зовнішньої роботи, яка використовує дещо незвичний процес прийняття рішень з несподіваними результатами. Отже, в дуже загальних рисах:

  • Стандартний вихід повинен бути кінцевим пристроєм, як визначено isatty().
  • Програма повинна мати можливість шукати запис для типу терміналу в базі даних termcap / terminfo.
  • І тому повинен бути термінал типу , щоб подивитися вгору. TERMЗмінна середовища повинна існувати і його значення повинно відповідати запису в базі даних.
  • Тому повинна бути база даних terminfo / termcap. У деяких реалізаціях підсистеми розташування бази даних termcap може бути визначене за допомогою TERMCAPзмінної середовища. Тож у деяких реалізаціях є друга змінна середовище.
  • Запис termcap / terminfo повинен зазначати, що тип терміналу підтримує кольори. У max_colorsтерміналі є поле. Він не встановлений для типів терміналів, які насправді не мають кольорових можливостей. Дійсно, існує умова terminfo про те, що для кожного кольорового типу терміналів існує ще одна запис із назвою -mабо -monoдодана до імені, яка не містить можливості кольорів.
  • Запис termcap / terminfo повинен передбачати шлях програми змінити кольори. Є терміни set_a_foregroundі set_a_backgroundполя.

Це трохи складніше, ніж просто перевірка isatty(). Це ще більше ускладнюється кількома речами:

  • Деякі програми додають параметри командного рядка або прапори конфігурації, які перекривають isatty()перевірку, так що програма завжди або ніколи не передбачає, що в якості вихідного сигналу є (кольоровий) термінал. Наприклад:
    • У GNU lsє параметр --colorкомандного рядка.
    • BSD lsрозглядає змінні середовища CLICOLOR(його відсутність означає ніколи ) та CLICOLOR_FORCE(його присутність означає завжди ), а також використовує параметр -Gкомандного рядка.
  • Деякі програми не використовують termcap / terminfo і мають провідні відповіді на значення TERM.
  • Не всі термінали використовують послідовності ECMA-48 або ISO 8613-6 SGR, які злегка названі "послідовностями втечі" ANSI, для зміни кольорів. Механізм termcap / terminfo фактично призначений для ізоляції додатків від прямого знання точних послідовностей управління. (Більше того, існує аргумент, що ніхто не використовує послідовності ISO 8613-6 SGR, оскільки всі погоджуються з помилкою використання напівколонки як роздільника для кольорових послідовностей RGB кольорів. Стандарт фактично визначає двокрапку.)

Як було сказано, GNU grepфактично проявляє деякі з цих додаткових складностей. Він не консультує termcap / terminfo, провідне з'єднання керуючих послідовностей для випромінювання та жорсткий провід відповіді на TERMзмінну середовища.

Порт Linux / Unix цього є цей код , який дозволяє colourization тільки тоді , коли TERMзмінна оточення існує і його значення не збігається Проводове ім'я dumb:

int
слід_колоризувати (недійсно)
{
  char const * t = getenv ("TERM");
  повернути t && strcmp (t, "німий")! = 0;
}

Таким чином , навіть якщо ваш TERMIS xterm-mono, GNU grepвирішить випускають квіти, навіть якщо інші програми , такі , як vimне буде.

Порт Win32 нього є цей код , який дозволяє colourization або коли TERMзмінна оточення НЕ існує , або якщо вона існує , і його значення не збігається Проводове ім'я dumb:

int
слід_колоризувати (недійсно)
{
  char const * t = getenv ("TERM");
  повернення! (t && strcmp (t, "німий") == 0);
}

grepПроблеми GNU з кольором

grepКольорованість GNU насправді горезвісна. Оскільки він насправді не справляє належну роботу зі створення термінального виходу, а просто звинувачує декілька послідовностей керованого проводу в різних точках свого виводу, марно сподіваючись, що це досить добре, він фактично показує неправильний вихід у певних обставинах.

У цих обставинах доводиться розфарбувати щось, що знаходиться з правого краю терміналу. Програми, які правильно виконують термінальний вихід, повинні враховувати автоматичні правильні поля. На додаток до незначної можливості того, що термінал може не мати їх (а саме auto_right_marginполе у ​​terminfo), поведінка терміналів, які мають автоматичні праві поля, часто слідує за прецедентом DEC VT від обгортання відкладених рядків . GNU grepцього не враховує, наївно очікуючи негайного загортання рядків , і його кольоровий вихід йде не так.

Кольоровий вихід - справа не проста.

Подальше читання


2
Як я розумію, ОП запитує про зміну поведінки, коли вихід перенаправляється; $TERMне пояснює цього. (Ваша відповідь загалом цікава, але я не думаю, що це стосується питання ...)
Стівен Кітт

дуже цікаво. Я хотів переглянути такий огляд того, як програми виявляють (або просто "вирішують"), що таке термінальні можливості вже кілька місяців. Це також дає зрозуміти, чому так важко знайти такий огляд - адже, здається, кожна програма робить це дещо інакше.
the_velour_fog

Пояснення, що означають обгортання відкладених рядків та негайне обгортання рядків разом із прикладом, що демонструє різницю, було б непоганим.
mosvy

0

unbufferКоманда з очікувати пакет де-пар на виході з першої програми і вхідні до другої програми.

Ви б використовували це так:

unbuffer myshellscript.sh | grep value

Я використовую його весь час з ansible і домашнім сценарієм ctee, щоб я міг бачити кольоровий вихід на терміналі, залишаючи файл журналу з нормальним (неокрашенным) виведенням.

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.