
ターミナルからカラー出力(またはなど)を出力するコマンドを実行するとls
、gcc
カラー出力が印刷されます。私の理解では、プロセスは実際には次のように出力しています。ANSIエスケープコード、ターミナルは色をフォーマットします。
ただし、別のプロセス (カスタム C アプリケーションなど) で同じコマンドを実行し、出力をアプリケーション自体の出力にリダイレクトすると、これらの色は保持されません。
プログラムは、テキストをカラー形式で出力するかどうかをどのように決定するのでしょうか? 環境変数はありますか?
答え1
答え2
環境変数はありますか?
はい。それはTERM
環境変数です。これは、決定プロセスの一部として使用されるものがいくつかあるためです。
ここで一般化するのは困難です。すべてのプログラムが単一の決定フローチャートに同意するわけではないからです。実際、grep
M. Kitt の回答で言及されている GNU は、予想外の結果をもたらすやや変わった決定プロセスを使用する外れ値の良い例です。したがって、非常に一般的な言葉で言えば、次のようになります。
- 標準出力は、 によって決定される端末デバイスである必要があります
isatty()
。 - プログラムは、termcap/terminfo データベース内の端末タイプのレコードを検索できる必要があります。
- だから、なれ検索する端末タイプ。
TERM
環境変数が存在し、その値がデータベース レコードと一致している必要があります。 - したがって、terminfo/termcapデータベースが必要です。サブシステムの実装によっては、termcapデータベースの場所を
TERMCAP
環境変数で指定できます。そのため、実装によっては、2番環境変数。 - 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
一度もない)とCLICOLOR_FORCE
その存在の意味いつも) 環境変数をサポートし、-G
コマンドライン オプションも備えています。
- GNU にはコマンドライン オプション
- いくつかのアプリケーションは 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
。
整数 色付けする必要がある (void) { char const *t = getenv ("TERM"); t を返します && strcmp (t, "dumb") != 0; }
したがって、 の場合でもTERM
、などの他のプログラムがそうでなくてもxterm-mono
、GNU は色を出力することを決定します。grep
vim
のWin32ポートにはこのコードがあります環境TERM
変数ではない存在する場合、または存在していてもその値がハードワイヤード名と一致しない場合dumb
:
整数 色付けする必要がある (void) { char const *t = getenv ("TERM"); 戻り値 ! (t && strcmp (t, "dumb") == 0); }
GNUgrep
の色に関する問題
GNUgrep
のカラー化は、実のところ悪名高いものです。端末出力を適切に構築するのではなく、出力のさまざまなポイントでいくつかのハードワイヤード制御シーケンスを単に挿入して、それで十分だろうという無駄な期待を抱くだけなので、特定の状況では実際に誤った出力が表示されます。
このような状況では、端末の右端にあるものを色付けする必要があります。端末出力を適切に行うプログラムは、自動右端マージンを考慮する必要があります。 加えて端末が自動右マージンを持たない可能性(auto_right_margin
terminfoのフィールド)はわずかですが、自動右マージンを持つ端末の動作は、DEC VTの先例に従うことが多いです。保留中の行折り返しGNUはgrep
これを考慮しておらず、単純に期待している。即時の行折り返し、色付きの出力は間違っています。
カラー出力は簡単なことではありません。
参考文献
- トーマス・E・ディッキー(2016年)。
grep --color
正しい出力が表示されない「」。xterm に関するよくある質問見えない島。 - ジョナサン・デ・ボイン・ポラード(2016年)。nosh ユーザー空間仮想端末のマニュアルページの斜体と色. ノッシュパッケージ。
答え3
unbuffer
からの命令期待するパッケージは、最初のプログラムからの出力と 2 番目のプログラムへの入力を切り離します。
次のように使用します:
unbuffer myshellscript.sh | grep value
私はいつもAnsibleと自作のcteeスクリプトを実行すると、ターミナル上でカラー出力を確認でき、ログ ファイルには通常の (カラー化されていない) 出力が残ります。
unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log