Shell

程序如何決定是否有彩色輸出?

  • June 13, 2019

當我從列印彩色輸出(例如lsgcc)的終端執行命令時,會列印彩色輸出。據我了解,這個過程實際上是輸出ANSI 轉義碼,終端格式化顏色。

但是,如果我通過另一個程序(例如自定義 C 應用程序)執行相同的命令並將輸出重定向到應用程序自己的輸出,則這些顏色不會持續存在。

程序如何決定是否輸出顏色格式的文本?有一些環境變數嗎?

大多數此類程序預設僅將顏色程式碼輸出到終端;他們檢查他們的輸出是否是 TTY,使用isatty(3). 通常有一些選項可以覆蓋此行為:在所有情況下禁用顏色,或在所有情況下啟用顏色。例如,對於 GNU grep--color=never禁用顏色並--color=always啟用它們。

在 shell 中,您可以使用-t test運算符執行相同的測試:[ -t 1 ]僅當標準輸出是終端時才會成功。

有一些環境變數嗎?

是的。它是TERM環境變數。這是因為有幾件事被用作決策過程的一部分。

在這裡很難一概而論,因為並非所有程序都同意一個決策流程圖。事實上grep,M. Kitt 的回答中提到的 GNU 是一個很好的異常值範例,它使用了一個有點不尋常的決策過程並產生了意想不到的結果。因此,籠統地說:

  • 標準輸出必須是終端設備,由isatty().
  • 程序必須能夠在 termcap/terminfo 數據庫中查找終端類型的記錄。
  • 因此,必須一個終端類型來查找。TERM環境變數必須存在且其值必須與數據庫記錄匹配。
  • 因此必須有一個 terminfo/termcap 數據庫。在子系統的某些實現中,可以使用TERMCAP環境變數指定 termcap 數據庫的位置。因此,在某些實現中,還有第二個環境變數。
  • termcap/terminfo 記錄必須聲明終端類型支持顏色。terminfo 中有一個max_colors欄位。它不是為實際上沒有顏色功能的終端類型設置的。實際上,有一個 terminfo 約定,對於每個可著色終端類型,都有另一條記錄,其名稱-m-mono附加到名稱中,表明沒有顏色功能。
  • termcap/terminfo 記錄必須為程序提供更改顏色的方式。terminfo中有set_a_foregroundset_a_background欄位。

這比檢查要復雜一些isatty()。有幾件事使它變得更加複雜:

  • 一些應用程序添加了覆蓋檢查的命令行選項或配置標誌isatty(),因此程序總是從不假定它有一個(可著色的)終端作為其輸出。舉些例子:

    • GNUls--color命令行選項。
    • BSDls查看CLICOLOR(它的缺席意味著never)和CLICOLOR_FORCE(它的存在意味著always)環境變數,並且還-G支持命令行選項。
  • 一些應用程序不使用 termcap/terminfo 並且對TERM.

  • 並非所有終端都使用 ECMA-48 或 ISO 8613-6 SGR 序列,這些序列稍微被誤稱為“ANSI 轉義序列”,用於更改顏色。termcap/terminfo 機制實際上旨在將應用程序與確切控制序列的直接知識隔離開來。(此外,有一個論點是沒有人使用 ISO 8613-6 SGR 序列,因為每個人都同意使用分號作為 RGB 顏色 SGR 序列的分隔符的錯誤。標準實際上指定了冒號。)

如前所述,GNUgrep實際上展示了其中一些額外的複雜性。它不諮詢 termcap/terminfo,硬連線要發出的控制序列,並硬連線對TERM環境變數的響應。

它的Linux/Unix 埠具有此程式碼,僅當TERM環境變數存在且其值與硬連線名稱不匹配時才啟用著色dumb

整數
應該著色(無效)
{
char const *t = getenv ("TERM");
返回 t && strcmp (t, "啞") != 0;
}

因此,即使您的TERMis xterm-mono,GNUgrep也會決定發出顏色,即使其他程序如vim不會。

它的Win32 埠有這個程式碼,當TERM環境變數存在或它存在並且它的值與硬連線名稱不匹配時,它可以啟用著色dumb

整數
應該著色(無效)
{
char const *t = getenv ("TERM");
返回 !(t && strcmp (t, "啞") == 0);
}

GNUgrep的顏色問題

GNUgrep的著色實際上是臭名昭著的。因為它實際上並沒有正確地建構終端輸出,而只是在其輸出的各個點上歸咎於一些硬連線控制序列,徒勞地希望這足夠好,它實際上在某些情況下顯示不正確的輸出。

在這些情況下,它必須對終端右側邊緣的東西進行著色。正確進行終端輸出的程序必須考慮自動右邊距。 除了終端可能沒有它們(即auto_right_marginterminfo 中的欄位)的可能性很小之外,具有自動右邊距的終端的行為通常遵循 DEC VT掛起換行的先例。GNUgrep沒有考慮到這一點,天真地期望立即換行,並且它的彩色輸出出錯了。

彩色輸出不是一件簡單的事情。

進一步閱讀

引用自:https://unix.stackexchange.com/questions/283983