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

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

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

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

程式如何決定是否輸出彩色格式的文字?是否有一些環境變數?

答案1

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

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

答案2

是否有一些環境變數?

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

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

  • 標準輸出必須是終端設備,由 決定isatty()
  • 該程式必須能夠在 termcap/terminfo 資料庫中尋找終端類型的記錄。
  • 所以因此必須有要尋找的終端類型。環境TERM變數必須存在且其值必須與資料庫記錄相符。
  • 因此必須有一個 terminfo/termcap 資料庫。在子系統的某些實作中,可以使用TERMCAP環境變數指定 termcap 資料庫的位置。所以在一些實現上有一個第二環境變數。
  • termcap/terminfo 記錄必須聲明終端類型支援顏色。max_colorsterminfo 中有一個欄位。它不是為實際上不具有顏色功能的終端類型設定的。事實上,有一個 terminfo 約定,對於每種可著色終端類型,都有另一個記錄-m-mono附加到名稱,表示沒有顏色功能。
  • termcap/terminfo 記錄必須提供程式改變顏色的方式。terminfo中有set_a_foreground和字段。set_a_background

這比僅僅檢查要複雜一些isatty()。它被製成更遠由幾件事複雜化:

  • 一些應用程式會新增命令列選項或配置標誌來覆蓋isatty()檢查,以便程式總是或者絕不假設它有一個(可著色的)終端作為其輸出。舉些例子:
    • GNUls--color命令列選項。
    • BSDls著眼於CLICOLOR(它的缺席意味著絕不) 和CLICOLOR_FORCE(其存在意義總是)環境變量,並且還支援-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");
  return t && strcmp(t, "啞巴") != 0;
}

因此,即使您的TERMxterm-mono,GNUgrep也會決定發出顏色,即使其他程式(例如)vim不會。

它的Win32埠有這個程式碼,當TERM環境變數才不是存在或當它存在並且其值與硬連線名稱不匹配時dumb

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

GNUgrep的顏色問題

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

在這些情況下,它必須對終端右側邊緣的某些內容進行著色。正確執行終端輸出的程式必須考慮自動右邊距。 另外終端可能沒有它們(即auto_right_marginterminfo 中的欄位)的可能性很小,具有自動右邊距的終端的行為通常遵循 DEC VT 先例待處理換行。 GNUgrep沒有考慮到這一點,天真地期待著立即換行,且其彩色輸出出錯。

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

進一步閱讀

答案3

unbuffer命令來自預計包將第一個程式的輸出與第二個程式的輸入解耦。

你可以像這樣使用它:

unbuffer myshellscript.sh | grep value

我一直將它與 ansible 和自製程序一起使用立方體腳本,以便我可以在終端機上看到顏色輸出,同時使日誌檔案保留正常(非彩色)輸出。

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

相關內容