當我從列印彩色輸出的終端(例如ls
或gcc
)執行命令時,將列印彩色輸出。據我了解,該過程實際上是輸出ANSI 轉義碼,終端格式化顏色。
但是,如果我透過另一個進程(例如自訂 C 應用程式)執行相同的命令並將輸出重定向到應用程式自己的輸出,則這些顏色不會持續存在。
程式如何決定是否輸出彩色格式的文字?是否有一些環境變數?
答案1
答案2
是否有一些環境變數?
是的。它是TERM
環境變數。這是因為有幾件事被用來作為決策過程的一部分。
這裡很難一概而論,因為並非所有程序都同意單一決策流程圖。事實上,grep
M. Kitt 的回答中提到的 GNU 是異常值的一個很好的例子,它使用了一些不尋常的決策過程,並產生了意想不到的結果。因此,一般來說:
- 標準輸出必須是終端設備,由 決定
isatty()
。 - 該程式必須能夠在 termcap/terminfo 資料庫中尋找終端類型的記錄。
- 所以因此必須有是要尋找的終端類型。環境
TERM
變數必須存在且其值必須與資料庫記錄相符。 - 因此必須有一個 terminfo/termcap 資料庫。在子系統的某些實作中,可以使用
TERMCAP
環境變數指定 termcap 資料庫的位置。所以在一些實現上有一個第二環境變數。 - termcap/terminfo 記錄必須聲明終端類型支援顏色。
max_colors
terminfo 中有一個欄位。它不是為實際上不具有顏色功能的終端類型設定的。事實上,有一個 terminfo 約定,對於每種可著色終端類型,都有另一個記錄-m
或-mono
附加到名稱,表示沒有顏色功能。 - termcap/terminfo 記錄必須提供程式改變顏色的方式。terminfo中有
set_a_foreground
和字段。set_a_background
這比僅僅檢查要複雜一些isatty()
。它被製成更遠由幾件事複雜化:
- 一些應用程式會新增命令列選項或配置標誌來覆蓋
isatty()
檢查,以便程式總是或者絕不假設它有一個(可著色的)終端作為其輸出。舉些例子:- GNU
ls
有--color
命令列選項。 - BSD
ls
著眼於CLICOLOR
(它的缺席意味著絕不) 和CLICOLOR_FORCE
(其存在意義總是)環境變量,並且還支援-G
命令列選項。
- GNU
- 一些應用程式不使用 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; }
因此,即使您的TERM
是xterm-mono
,GNUgrep
也會決定發出顏色,即使其他程式(例如)vim
不會。
這它的Win32埠有這個程式碼,當TERM
環境變數才不是存在或當它存在並且其值與硬連線名稱不匹配時dumb
:
整數 應該著色(空) { char const *t = getenv("TERM"); 返回 ! (t && strcmp(t, "啞巴") == 0); }
GNUgrep
的顏色問題
GNUgrep
的彩色化其實是臭名昭著的。因為它實際上並沒有正確地構建終端輸出,而只是在其輸出中的各個點上指責一些硬連線控制序列,徒勞地希望這足夠好,所以它實際上在某些情況下顯示不正確的輸出。
在這些情況下,它必須對終端右側邊緣的某些內容進行著色。正確執行終端輸出的程式必須考慮自動右邊距。 另外終端可能沒有它們(即auto_right_margin
terminfo 中的欄位)的可能性很小,具有自動右邊距的終端的行為通常遵循 DEC VT 先例待處理換行。 GNUgrep
沒有考慮到這一點,天真地期待著立即換行,且其彩色輸出出錯。
彩色輸出並不是一件簡單的事。
進一步閱讀
- 托馬斯·E·迪基 (2016)。 」
grep --color
不顯示正確的輸出」。xterm 常見問題解答。看不見的島。 - 喬納森·德博因·波拉德 (2016)。nosh 使用者空間虛擬終端機上手冊頁中的斜體和顏色。小吃包。
答案3
該unbuffer
命令來自預計包將第一個程式的輸出與第二個程式的輸入解耦。
你可以像這樣使用它:
unbuffer myshellscript.sh | grep value
我一直將它與 ansible 和自製程序一起使用立方體腳本,以便我可以在終端機上看到顏色輸出,同時使日誌檔案保留正常(非彩色)輸出。
unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log