端末を設定したいのでstderr
、とは異なる色で印刷されstdout
ます。たぶん赤。これにより、2つを区別しやすくなります。
これを設定する方法はあります.bashrc
か?そうでない場合、これも可能ですか?
注:この質問はと合併した他を求めているstderr
、stdout
とユーザー入力のエコーで出力されるように3色展開。回答はどちらの質問にも対応している可能性があります。
端末を設定したいのでstderr
、とは異なる色で印刷されstdout
ます。たぶん赤。これにより、2つを区別しやすくなります。
これを設定する方法はあります.bashrc
か?そうでない場合、これも可能ですか?
注:この質問はと合併した他を求めているstderr
、stdout
とユーザー入力のエコーで出力されるように3色展開。回答はどちらの質問にも対応している可能性があります。
回答:
これは、画面にstderrのみを表示するハードバージョンですが、stdoutとstderrの両方をfileに書き込みます。
ターミナルで実行されているアプリケーションは、単一のチャネルを使用して通信します。アプリケーションには、stdoutとstderrの2つの出力ポートがありますが、どちらも同じチャネルに接続されています。
それらの1つを別のチャネルに接続し、そのチャネルに色を追加し、2つのチャネルをマージできますが、これにより2つの問題が発生します。
␛[31m
「赤い前景に切り替える」という意味です。これは、stderrの出力が表示されているときにstdout宛ての出力が到着した場合、出力の色が正しくないことを意味します。(さらに悪いことに、エスケープシーケンスの途中でチャネルの切り替えがある場合は、ゴミが表示されます。)原則として、2つのptys¹で同期的にリッスンするプログラムを作成し(つまり、1つのチャネルで入力を受け入れず、他のチャネルで出力を処理します)、適切な色変更命令ですぐに端末に出力できます。端末と対話するプログラムを実行する機能が失われます。このメソッドの実装については知りません。
別の可能なアプローチはwrite
、でロードされたライブラリでシステムコールを呼び出すすべてのlibc関数をフックすることにより、プログラムに適切な色変更シーケンスを出力させることLD_PRELOAD
です。既存の実装に対するシックルの回答、またはを活用する混合アプローチに対するステファンシャゼラスの回答を参照してくださいstrace
。
それが該当するかどう実際には、私のようなパターンベースのカラー表示機能にstdoutとstderrの配管にリダイレクト示唆colortailまたはmultitail、またはのような専用の色付け機能(colorizers)colorgccまたはcolormake。
¹ 擬似端末。バッファリングのため、パイプは機能しません。ソースがバッファに書き込むことができ、カラーライザとの同期が崩れます。
LD_PRELOAD
傍受するトリックをwrite
IMO、最も適切であると思われる(。しかし、その後、再び、特定の* nixの味の違いがあるかもしれません)の呼び出しを
write
ほとんどのアプリケーションは直接呼び出さないとして単独では機能しないだろうが、いくつかの共有ライブラリ(等からの別の関数printf
の元を呼ぶだろう)write
write
syscallラッパーをフックすることを考えていました。Glibcの他の関数にインライン化されていますか?
チェックアウトしstderred
ます。これはの呼び出しLD_PRELOAD
にフックして、端末へのすべての出力を色付けするために使用します。(デフォルトでは赤。)libc
write()
stderr
ユーザー入力の色付けは難しい場合があります。半分の場合、ターミナルドライバーによって出力されるため(ローカルエコーを使用)、その場合、そのターミナルで実行中のアプリケーションは、ユーザーがテキストを入力し、それに応じて出力色を変更するタイミングを認識できません。(カーネル内の)疑似端末ドライバーのみが知っています(端末エミュレーター(xtermなど)はキーを押すといくつかの文字を送信し、端末ドライバーはエコーのためにいくつかの文字を送り返しますが、xtermはそれらがローカルエコーまたはアプリケーションが擬似端末のスレーブ側に出力したもの)。
そして、ターミナルドライバーにエコーしないように指示する別のモードがありますが、今回はアプリケーションが何かを出力します。アプリケーション(gdb、bashなどのreadlineを使用するアプリケーションなど)は、stdoutまたはstderrで送信する場合があり、ユーザー入力をエコーバックする以外の目的で出力するものと区別するのが困難になります。
次に、アプリケーションの標準出力と標準エラーを区別するために、いくつかのアプローチがあります。
それらの多くは、コマンドstdoutおよびstderrをパイプにリダイレクトし、それらのパイプがアプリケーションによって読み取られて色付けされます。これには2つの問題があります。
別のアプローチは、stdoutとstdinを色付けするようにアプリケーションを変更することです。多くの場合、これは不可能または現実的ではありません。
次に、(動的にリンクされたアプリケーションの)トリックは、何かを出力するためにアプリケーションによって呼び出される出力関数をハイジャックする(sickillの答えの$LD_PRELOAD
ように使用する)ことができ、何かを出力するかどうかに基づいて前景色を設定するコードを含めるstderrまたはstdoutで。ただし、Cライブラリや、stdoutまたはstderr(printf、puts、perror ...)に何かを書き込む可能性のあるアプリケーションによって直接呼び出されるsyscall を実行する他のライブラリからすべての可能な関数をハイジャックすることを意味します、その動作を変更する場合があります。write(2)
別のアプローチは、としてPTRACEのトリックを使用することができstrace
たりgdb
、私たち自身を毎回フックするために行うwrite(2)
システムコールが呼び出されたのかどうかに基づいて、出力カラー設定write(2)
ファイルディスクリプタ1または2であるが。
ただし、それは非常に大きなことです。
私がちょうど遊んでいたトリックstrace
は、write(2)
fd 1または2。
見てからstrace
ソースコードを、我々はそれが出力のすべてを介して行われていることがわかりますvfprintf
機能。必要なのは、その機能をハイジャックすることだけです。
LD_PRELOADラッパーは次のようになります。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
int vfprintf(FILE *outf, const char *fmt, va_list ap)
{
static int (*orig_vfprintf) (FILE*, const char *, va_list) = 0;
static int c = 0;
va_list ap_orig;
va_copy(ap_orig, ap);
if (!orig_vfprintf) {
orig_vfprintf = (int (*) (FILE*, const char *, va_list))
dlsym (RTLD_NEXT, "vfprintf");
}
if (strcmp(fmt, "%ld, ") == 0) {
int fd = va_arg(ap, long);
switch (fd) {
case 2:
write(2, "\e[31m", 5);
c = 1;
break;
case 1:
write(2, "\e[32m", 5);
c = 1;
break;
}
} else if (strcmp(fmt, ") ") == 0) {
if (c) write(2, "\e[m", 3);
c = 0;
}
return orig_vfprintf(outf, fmt, ap_orig);
}
次に、次のようにコンパイルします。
cc -Wall -fpic -shared -o wrap.so wrap.c -ldl
そしてそれを次のように使用します:
LD_PRELOAD=/path/to/wrap.so strace -qfo /dev/null -e write -s 0 env -u LD_PRELOAD some-cmd
に置き換えるsome-cmd
とbash
、bashプロンプトと入力内容が赤(stderr)zsh
で表示され、黒で表示されます(zshはstderrを新しいfdにコピーしてプロンプトとエコーを表示するため)。
期待しないアプリケーション(色を使用するアプリケーションなど)でも驚くほどうまく機能するようです。
カラーモードはstrace
、端末であると想定されるの標準エラー出力に出力されます。アプリケーションがそのstdoutまたはstderrをリダイレクトする場合、ハイジャックされたstraceはターミナルでカラーリングエスケープシーケンスを書き続けます。
このソリューションには制限があります。
strace
:パフォーマンスの問題、strace
またはそのような他のPTRACEコマンドを実行できないgdb
、またはsetuid / setgidの問題write
個々のプロセスの標準出力/標準エラーのsに基づいた色付けです。だから、例えば、でsh -c 'echo error >&2'
、error
あるため、緑だろうecho
に出力するその標準出力(SHのstderrにリダイレクトSH、しかし、すべてのstraceのがAで見ていますwrite(1, "error\n", 6)
)。そして、でsh -c 'seq 1000000 | wc'
、seq
ロットまたはないwrite
にSをその標準出力なので、ラッパーは端末にエスケープシーケンス(見えない)の多くをoutputingなってしまいます。strace $CMD | vim -c ':set syntax=strace' -
。
これは、私がしばらく前に行った概念実証です。
zshでのみ機能します。
# make standard error red
rederr()
{
while read -r line
do
setcolor $errorcolor
echo "$line"
setcolor normal
done
}
errorcolor=red
errfifo=${TMPDIR:-/tmp}/errfifo.$$
mkfifo $errfifo
# to silence the line telling us what job number the background job is
exec 2>/dev/null
rederr <$errfifo&
errpid=$!
disown %+
exec 2>$errfifo
また、setcolorという関数があることを前提としています。
簡易版:
setcolor()
{
case "$1" in
red)
tput setaf 1
;;
normal)
tput sgr0
;;
esac
}
exec 2> >(rederr)
。どちらのバージョンにも、回答で述べたように、行の並べ替えと出力の破損のリスク(特に長い行)の問題があります。
seterr
関数ではなく、スタンドアロンスクリプトである必要があります。