プログラムはカラー出力かどうかをどのように決定しますか?

プログラムはカラー出力かどうかをどのように決定しますか?

lsカラー出力(たとえば、または)を印刷する端末でコマンドを実行すると、gccカラー出力が印刷されます。私が理解しているように、プロセスは実際に出力されます。ANSIエスケープコード、ターミナル書式の色。

ただし、別のプロセス(カスタムCアプリケーションなど)を介して同じコマンドを実行し、出力をアプリケーションの独自の出力にリダイレクトしても色は保持されません。

プログラムは、テキストをカラー形式で出力するかどうかをどのように決定しますか?環境変数はありますか?

答え1

デフォルトでは、ほとんどのプログラムはカラーコードを端末に出力します。以下を使用して、出力がTTYであることを確認します。isatty(3)。通常、この動作をオーバーライドするオプションがあります。すべての状況で色を無効にするか、すべての状況で色を有効にします。grepたとえば、GNUの場合、--color=never色を無効にして--color=always有効にします。

シェルでは、以下を使用して同じテストを実行できます。-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()プログラムがチェックを無視するようにします。いつもまたはいいえ出力として(着色可能な)端末があるとします。いくつかの例:
    • GNUにはコマンドラインオプションがlsあります。--color
    • BSDは(部材lsCLICOLORいいえ)そしてCLICOLOR_FORCE(その存在の意味いつも)環境変数であり、-Gコマンドラインオプションもサポートしています。
  • 一部アプリケーションはtermcap / terminfoを使用せず、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

整数
色を指定する必要があります(null)。
{
  char const *t = getenv("TERM");
  return t && strcmp(t, "dumb") != 0;
}

したがって、あなたのプログラムがそうであっても、TERMGNUxterm-monogrep他のプログラム(例えば)が色を出さなくても色を出すことにしますvim

これWin32 ポートには次のコードがあります。TERM、これは環境変数に色を割り当てることによって達成できます。確かに存在または存在し、その値がハードワイヤード名と一致しない場合dumb

整数
色を指定する必要があります(null)。
{
  char const *t = getenv("TERM");
  返品! (t && strcmp(t, "dumb") == 0);
}

GNUgrepカラーの問題

GNUgrepのカラーリングは実際に悪名高いです。実際には、端末出力を正しく作成せずに十分であるという無駄な希望で、出力のさまざまな点でいくつかのハードワイヤ制御シーケンスを非難するため、実際には出力が間違って表示されます。

この場合、端末の右端に色を付ける必要があります。ターミナル出力を正しく実行するプログラムは、自動右マージンを考慮する必要があります。 また端末に対応するフィールド(つまり、terminfoのフィールド)がない可能性が低くなりますauto_right_margin。自動右マージンを持つ端末の動作は通常、DEC VT 先例に従います。改行待ち。 GNUはgrepこれを考慮せず、素直に予想した。すぐに改行、色出力が間違っています。

カラー出力は単なる問題ではありません。

追加読書

答え3

このunbufferコマンドは以下から来ます。予想されるパッケージは、最初のプログラムの出力と2番目のプログラムの入力を分離します。

次のように使用できます。

unbuffer myshellscript.sh | grep value

私はansibleとhomebrewと一緒に使用しています。立方体ログファイルを通常の(非カラー)出力として残し、端末からカラー出力を表示できるようにスクリプトします。

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

関連情報