프로그램은 컬러 출력 여부를 어떻게 결정합니까?

프로그램은 컬러 출력 여부를 어떻게 결정합니까?

ls컬러 출력(예: 또는 ) 을 인쇄하는 터미널에서 명령을 실행하면 gcc컬러 출력이 인쇄됩니다. 내 이해에 따르면 프로세스가 실제로 출력되고 있습니다.ANSI 이스케이프 코드, 터미널은 색상 형식을 지정합니다.

그러나 다른 프로세스(예: 사용자 정의 C 응용 프로그램)에서 동일한 명령을 실행하고 출력을 응용 프로그램의 자체 출력으로 리디렉션하면 이러한 색상이 지속되지 않습니다.

프로그램은 텍스트를 색상 형식으로 출력할지 여부를 어떻게 결정합니까? 환경변수가 있나요?

답변1

대부분의 프로그램은 기본적으로 색상 코드만 터미널에 출력합니다. 다음을 사용하여 출력이 TTY인지 확인합니다.isatty(3). 일반적으로 이 동작을 재정의하는 옵션이 있습니다. 모든 경우에 색상을 비활성화하거나 모든 경우에 색상을 활성화합니다. grep예를 들어 GNU의 경우 --color=never색상을 비활성화하고 --color=always활성화합니다.

쉘에서는 다음을 사용하여 동일한 테스트를 수행할 수 있습니다.-t test연산자: [ -t 1 ]표준 출력이 터미널인 경우에만 성공합니다.

답변2

환경변수가 있나요?

예. 환경변수 입니다 TERM. 의사결정 과정의 일부로 사용되는 것들이 여러 가지 있기 때문입니다.

모든 프로그램이 단일 결정 흐름도에 동의하는 것은 아니기 때문에 여기서 일반화하기는 어렵습니다. 실제로 grepM. Kitt의 답변에서 언급된 GNU는 예상치 못한 결과가 있는 다소 특이한 결정 프로세스를 사용하는 이상치의 좋은 예입니다. 따라서 매우 일반적인 용어로 말하면 다음과 같습니다.

  • 표준 출력은 에서 결정한 대로 터미널 장치여야 합니다 isatty().
  • 프로그램은 termcap/terminfo 데이터베이스에서 터미널 유형에 대한 기록을 검색할 수 있어야 합니다.
  • 그러므로 반드시BE조회할 터미널 유형입니다. 환경 TERM변수가 존재해야 하며 해당 값은 데이터베이스 레코드와 일치해야 합니다.
  • 따라서 terminfo/termcap 데이터베이스가 있어야 합니다. 하위 시스템의 일부 구현에서는 환경 변수를 사용하여 termcap 데이터베이스의 위치를 ​​지정할 수 있습니다 TERMCAP. 따라서 일부 구현에는두번째환경 변수.
  • termcap/terminfo 레코드에는 터미널 유형이 색상을 지원함을 명시해야 합니다. max_colorsterminfo에 필드 가 있습니다 . 실제로 색상 기능이 없는 터미널 유형에는 설정되지 않습니다. 실제로 모든 색상 지정 터미널 유형에 대해 색상 기능이 없음을 명시하는 이름이 -m있거나 -mono이름에 추가되는 또 다른 기록이 있다는 terminfo 규칙이 있습니다 .
  • termcap/terminfo 레코드는 프로그램이 색상을 변경하는 방법을 제공해야 합니다. terminfo에는 set_a_foreground및 필드 가 있습니다 .set_a_background

단순히 확인하는 것보다 조금 더 복잡합니다 isatty(). 만들어진다더 나아가여러 가지로 인해 복잡해졌습니다.

  • 일부응용 프로그램은 검사를 무시하는 명령줄 옵션이나 구성 플래그를 추가하여 프로그램 isatty()언제나또는절대출력으로 (색상 지정 가능한) 터미널이 있다고 가정합니다. 예를 들어:
    • GNU에는 명령줄 옵션이 ls있습니다 .--color
    • BSD는 (부재 의미를 ls살펴 봅니다.CLICOLOR절대) 및 CLICOLOR_FORCE(그 존재 의미언제나) 환경 변수 및 -G명령줄 옵션도 제공합니다.
  • 일부애플리케이션은 termcap/terminfo를 사용하지 않으며 TERM.
  • 모든 터미널이 색상 변경을 위해 "ANSI 이스케이프 시퀀스"라고 약간 잘못 명명된 ECMA-48 또는 ISO 8613-6 SGR 시퀀스를 사용하는 것은 아닙니다. termcap/terminfo 메커니즘은 실제로 정확한 제어 순서에 대한 직접적인 지식으로부터 애플리케이션을 보호하도록 설계되었습니다. (게다가 다음과 같은 주장도 있습니다.아무도ISO 8613-6 SGR 시퀀스를 사용합니다.모두가 버그에 동의합니다RGB 색상 SGR 시퀀스의 구분 기호로 세미콜론을 사용합니다. 표준에서는 실제로 콜론을 지정합니다.)

언급한 대로 GNU는 grep실제로 이러한 추가적인 복잡성 중 일부를 보여줍니다. termcap/terminfo를 참조하지 않고, 방출할 제어 시퀀스를 하드배선하고, TERM환경 변수에 대한 응답을 하드배선합니다.

그만큼Linux/Unix 포트에는 다음 코드가 있습니다.TERM, 환경 변수가 존재하고 해당 값이 하드와이어된 이름과 일치하지 않는 경우에만 색상화를 활성화합니다.dumb .

정수
should_colorize (무효)
{
  char const *t = getenv ("TERM");
  return t && strcmp (t, "dumb") != 0;
}

TERM따라서 귀하가 이다 하더라도 xterm-monoGNU는 grep색상을 방출하기로 결정합니다. 다른 프로그램에서는 vim그렇지 않더라도 마찬가지입니다.

그만큼Win32 포트에는 다음 코드가 있습니다.TERM, 환경 변수가 있을 때 색상화를 가능하게 합니다.하지 않습니다존재하거나 존재하고 해당 값이 하드와이어된 이름과 일치하지 않는 경우 dumb:

정수
should_colorize (무효)
{
  char const *t = getenv ("TERM");
  반품 ! (t && strcmp (t, "멍청함") == 0);
}

GNU grep의 색상 문제

GNU grep의 색상화는 실제로 악명 높습니다. 실제로 터미널 출력을 구성하는 적절한 작업을 수행하지 않고 출력의 여러 지점에서 몇 가지 내장된 제어 시퀀스를 비난하기 때문에 그것이 충분할 것이라는 헛된 희망 때문에 특정 상황에서는 실제로 잘못된 출력을 표시합니다.

이러한 상황에서는 터미널의 오른쪽 여백에 있는 항목에 색상을 지정해야 합니다. 터미널 출력을 제대로 수행하는 프로그램은 자동 오른쪽 여백을 고려해야 합니다. 게다가터미널에 이러한 항목이 없을 수도 있는 약간의 가능성(즉, auto_right_marginterminfo의 필드)에 대해 자동 오른쪽 여백이 있는 터미널의 동작은 종종 DEC VT의 선례를 따릅니다.보류 중인 줄 바꿈. GNU는 grep이를 설명하지 않으며 순진하게 기대합니다.즉시 줄 바꿈, 컬러 출력이 잘못되었습니다.

컬러 출력은 간단한 일이 아닙니다.

추가 읽기

답변3

unbuffer의 명령 은예상하다패키지는 첫 번째 프로그램의 출력과 두 번째 프로그램의 입력을 분리합니다.

다음과 같이 사용할 수 있습니다.

unbuffer myshellscript.sh | grep value

나는 ansible과 homebrewed를 항상 사용합니다.씨티스크립트를 사용하여 로그 파일을 일반(색상화되지 않은) 출력으로 남겨두고 터미널에서 색상 출력을 볼 수 있습니다.

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

관련 정보