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


17

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

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

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

답변:


25

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

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


프로세스가 tty라는 시작된 응용 프로그램을 속일 수있는 방법이 있습니까?
Chris Smith

4
unix.stackexchange.com/questions/249723 , chris13523 에서 묻고 대답했습니다 . 그런데 코멘트는 실제로 후속 질문을위한 장소가 아닙니다.
JdeBP

1
@ chris13524는 JdeBP의 링크를 참조하십시오. 많은 경우 프로그램이 컬러 코드를 출력하도록 강제 할 수도 있습니다 (업데이트 된 답변 참조).
Stephen Kitt

13

환경 변수가 있습니까?

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

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

  • 에 의해 결정된 표준 출력은 터미널 장치 여야합니다 isatty().
  • 프로그램은 termcap / terminfo 데이터베이스에서 터미널 유형에 대한 레코드를 찾을 수 있어야합니다.
  • 그래서 그러므로이 있어야 찾아 볼 수있는 단말기 유형. TERM환경 변수가 존재해야하며 그 값은 데이터베이스 레코드와 일치해야합니다.
  • 따라서 terminfo / termcap 데이터베이스가 있어야합니다. 서브 시스템의 일부 구현에서 TERMCAP환경 변수를 사용하여 termcap 데이터베이스의 위치를 ​​지정할 수 있습니다 . 따라서 일부 구현에는 두 번째 환경 변수가 있습니다.
  • termcap / terminfo 레코드는 터미널 유형이 색상을 지원한다고 명시해야합니다. 있다 max_colors필드의 terminfo에. 실제로 색상 기능이없는 터미널 유형에는 설정되어 있지 않습니다. 실제로 모든 채색 가능한 터미널 유형에 대해 색상 기능이 없음을 나타내는 이름에 추가 -m되거나 -mono추가 된 레코드가 있다는 용어 정보 규칙이 있습니다.
  • termcap / terminfo 레코드는 프로그램이 색상을 변경하는 방법을 제공해야합니다. terminfo에 set_a_foregroundset_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 메커니즘은 실제로 정확한 제어 시퀀스에 대한 직접적인 지식으로부터 응용 프로그램을 격리하도록 설계되었습니다. 또한 RGB 색상 SGR 시퀀스의 구분 기호로 세미콜론을 사용 하는 버그동의 하기 때문에 아무도 ISO 8613-6 SGR 시퀀스를 사용 하지 않는다는 주장도 있습니다 . 표준은 실제로 콜론을 지정합니다.

언급했듯이 GNU는 grep실제로 이러한 추가 복잡성 중 일부를 나타냅니다. termcap / terminfo를 참조하지 않고, 제어 할 수 있도록 제어 시퀀스를 배선하고, TERM환경 변수에 대한 응답을 배선 합니다.

그것의 Linux / Unix 포트는이 코드 를 가지고 있는데, 이것은 TERM환경 변수가 존재하고 그 값이 하드 와이어드 이름과 일치하지 않을 때만 채색을 가능하게 합니다 dumb:

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

그래서 심지어 경우 TERMIS xterm-mono, GNU는 grep심지어 다른 프로그램하지만 같은 발광 색상을 결정합니다 vim하지 않습니다.

그것Win32 포트는이 코드 를 가지고 있는데, 이것은 TERM환경 변수 존재 하지 않거나 존재하고 그 값이 하드 와이어드 이름과 일치하지 않을 때 채색을 가능하게 합니다 dumb:

int
should_colorize (void)
{
  char const * t = getenv ( "TERM");
  돌아와! (t && strcmp (t, "dumb") == 0);
}

grep색깔에 관한 GNU 의 문제

GNU grep의 채색은 실제로 악명이 높습니다. 실제로 터미널 출력을 구성하는 적절한 작업을 수행하지는 않지만 헛된 출력의 여러 지점에서 몇 가지 고정 배선 제어 시퀀스를 비난하기 때문에 실제로는 특정 상황에서 잘못된 출력을 표시합니다.

이러한 상황은 터미널의 오른쪽 가장자리에있는 것을 채색해야합니다. 터미널 출력을 올바르게 수행하는 프로그램은 자동 오른쪽 여백을 고려해야합니다. 또한 터미널 힘이 그들을 가지고하지 않는 것이 약간의 가능성합니다 (즉 auto_right_marginterminfo의 필드), 자동 오른쪽 여백이 있습니까 단말기의 동작은 종종 년 12 VT 전례 다음 자동 줄 바꿈을 보류중인 . GNU grep는 이것을 즉시 설명하지는 않았지만 순식간에 줄 바꿈을 기대 하고 색상 출력이 잘못되었습니다.

컬러 출력은 단순한 것이 아닙니다.

추가 자료


2
내가 이해하는 것처럼 OP는 출력이 리디렉션 될 때 동작의 변화에 ​​대해 묻습니다. $TERM설명하지 않습니다. (여러분의 대답은 일반적으로 흥미롭지 만 질문에 대한 답은 아닙니다 ...)
Stephen Kitt

매우 흥미로운. 나는 프로그램이 몇 달 동안 터미널 기능이 무엇인지 발견하는 (또는 단순히 "결정") 방법에 대해 이와 같은 개요를 원했다. 이것은 또한 각각의 프로그램이 약간 다르게하는 것처럼 보이기 때문에 왜 이렇게 개요를 찾기가 어려운지에 대한 통찰력을 제공합니다.
the_velour_fog

무엇에 대한 설명 중인 자동 줄 바꿈즉각적인 라인 랩 의 차이를 설명하는 예제와 평균 함께 좋은 것입니다.
mosvy

0

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

다음과 같이 사용하십시오.

unbuffer myshellscript.sh | grep value

로그 파일을 정상적인 (색이 아닌) 출력으로 남겨두고 터미널에서 색상 출력을 볼 수 있도록 항상 사용 가능한 자체 제작 ctee 스크립트와 함께 사용합니다.

unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.