程序如何決定是否有彩色輸出?
當我從列印彩色輸出(例如
ls
或gcc
)的終端執行命令時,會列印彩色輸出。據我了解,這個過程實際上是輸出ANSI 轉義碼,終端格式化顏色。但是,如果我通過另一個程序(例如自定義 C 應用程序)執行相同的命令並將輸出重定向到應用程序自己的輸出,則這些顏色不會持續存在。
程序如何決定是否輸出顏色格式的文本?有一些環境變數嗎?
大多數此類程序預設僅將顏色程式碼輸出到終端;他們檢查他們的輸出是否是 TTY,使用
isatty(3)
. 通常有一些選項可以覆蓋此行為:在所有情況下禁用顏色,或在所有情況下啟用顏色。例如,對於 GNUgrep
,--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_foreground
和set_a_background
欄位。這比檢查要復雜一些
isatty()
。有幾件事使它變得更加複雜:
一些應用程序添加了覆蓋檢查的命令行選項或配置標誌
isatty()
,因此程序總是或從不假定它有一個(可著色的)終端作為其輸出。舉些例子:
- GNU
ls
有--color
命令行選項。- BSD
ls
查看CLICOLOR
(它的缺席意味著never)和CLICOLOR_FORCE
(它的存在意味著always)環境變數,並且還-G
支持命令行選項。一些應用程序不使用 termcap/terminfo 並且對
TERM
.並非所有終端都使用 ECMA-48 或 ISO 8613-6 SGR 序列,這些序列稍微被誤稱為“ANSI 轉義序列”,用於更改顏色。termcap/terminfo 機制實際上旨在將應用程序與確切控制序列的直接知識隔離開來。(此外,有一個論點是沒有人使用 ISO 8613-6 SGR 序列,因為每個人都同意使用分號作為 RGB 顏色 SGR 序列的分隔符的錯誤。標準實際上指定了冒號。)
如前所述,GNU
grep
實際上展示了其中一些額外的複雜性。它不諮詢 termcap/terminfo,硬連線要發出的控制序列,並硬連線對TERM
環境變數的響應。它的Linux/Unix 埠具有此程式碼,僅當
TERM
環境變數存在且其值與硬連線名稱不匹配時才啟用著色dumb
:整數 應該著色(無效) { char const *t = getenv ("TERM"); 返回 t && strcmp (t, "啞") != 0; }
因此,即使您的
TERM
isxterm-mono
,GNUgrep
也會決定發出顏色,即使其他程序如vim
不會。它的Win32 埠有這個程式碼,當
TERM
環境變數不存在或它存在並且它的值與硬連線名稱不匹配時,它可以啟用著色dumb
:整數 應該著色(無效) { char const *t = getenv ("TERM"); 返回 !(t && strcmp (t, "啞") == 0); }
GNU
grep
的顏色問題GNU
grep
的著色實際上是臭名昭著的。因為它實際上並沒有正確地建構終端輸出,而只是在其輸出的各個點上歸咎於一些硬連線控制序列,徒勞地希望這足夠好,它實際上在某些情況下顯示不正確的輸出。在這些情況下,它必須對終端右側邊緣的東西進行著色。正確進行終端輸出的程序必須考慮自動右邊距。 除了終端可能沒有它們(即
auto_right_margin
terminfo 中的欄位)的可能性很小之外,具有自動右邊距的終端的行為通常遵循 DEC VT掛起換行的先例。GNUgrep
沒有考慮到這一點,天真地期望立即換行,並且它的彩色輸出出錯了。彩色輸出不是一件簡單的事情。
進一步閱讀
- 托馬斯·E·迪基 (2016)。“
grep --color
沒有顯示正確的輸出”。xterm 常見問題解答。隱形島。- 喬納森·德博因·波拉德 (2016)。nosh 使用者空間虛擬終端上的手冊頁中的斜體和顏色。小吃包。