stderr
がstdout
とは異なる色で印刷されるように端末を設定したいと思います。多分赤。これにより、2つを区別しやすくなります。
これを.bashrc
で構成する方法はありますか?そうでない場合、これは可能ですか?
注:この質問は、stderr
、stdout
-を求める another とマージされました- およびユーザー入力エコー種類の色で出力されます。回答はどちらかの質問に対処している可能性があります。
これは stderrのみを画面に表示するが、stdoutとstderrの両方をファイルに書き込む のハードバージョンです。
端末で実行されているアプリケーションは、単一のチャネルを使用して通信します。アプリケーションには2つの出力ポート、stdoutとstderrがありますが、どちらも同じチャネルに接続されています。
それらの1つを別のチャネルに接続し、そのチャネルに色を追加し、2つのチャネルをマージできますが、これにより2つの問題が発生します。
␛[31m
は、「赤い前景に切り替える」ことを意味します。これは、stderrへの出力が表示されているのと同じようにstdout宛ての出力が到着すると、出力の色が間違っていることを意味します。 (さらに悪いことに、エスケープシーケンスの途中にチャネル切り替えがあると、ゴミが表示されます。)原則として、2つのptyをリッスンして(つまり、一方のチャネルで入力を受け付けず、もう一方のチャネルで出力を処理している)2つのptyをリッスンし、適切な色変更命令を使用して即座に端末に出力するプログラムを作成できます。端末と対話するプログラムを実行する能力を失います。このメソッドの実装については知りません。
LD_PRELOAD
がロードされたライブラリでwrite
システムコールを呼び出すすべてのlibc関数をフックすることにより、プログラムに適切な色変更シーケンスを出力させることもできます。 。既存の実装については sickillの回答 を参照してください。または、既存の実装については StéphaneChazelasの回答 を参照してください。 strace
を活用する混合アプローチ。
実際には、それが当てはまる場合は、stderrをstdoutにリダイレクトし、 colortail や multitail 、または colorgcc または colormakeなどの特殊用途のカラー化ツール 。
¹ 疑似端末。バッファリングのため、パイプは機能しませんでした。ソースがバッファに書き込む可能性があり、これにより、カラライザとの同期性が失われます。
チェックアウト stderred
。 _LD_PRELOAD
_を使用してlibc
のwrite()
呼び出しにフックし、端末に送信されるすべてのstderr
出力を色分けします。 (デフォルトでは赤で表示されます。)
ユーザー入力のカラーリングは、半分の場合、ターミナルドライバー(ローカルエコーを使用)によって出力されるため困難です。その場合、そのターミナルで実行されているアプリケーションは、ユーザーがテキストを入力するタイミングを認識できず、それに応じて出力カラーを変更できません。 。 (カーネル内の)疑似ターミナルドライバーだけが知っています(xtermのようなターミナルエミュレーターがキーを押すといくつかの文字を送信し、ターミナルドライバーはエコー用にいくつかの文字を返すことがありますが、xtermはそれらがローカルエコーまたはアプリケーションが疑似端末のスレーブ側に出力したもの)。
そして、ターミナルドライバーにエコーしないように指示する別のモードがありますが、今回のアプリケーションは何かを出力します。アプリケーション(gdb、bashなどのreadlineを使用するアプリケーションなど)は、ユーザー入力をエコーバックする以外に出力するものと区別するのが難しいstdoutまたはstderrで送信する場合があります。
次に、アプリケーションのstdoutをstderrと区別するために、いくつかの方法があります。
それらの多くは、コマンドstdoutおよびstderrをパイプにリダイレクトし、アプリケーションがパイプを読み取って色を付けることを含みます。これには2つの問題があります。
別のアプローチは、アプリケーションを変更して、標準出力と標準入力に色を付けることです。多くの場合、それは不可能または現実的ではありません。
次に、トリック(動的にリンクされたアプリケーションの場合)は、ハイジャック($LD_PRELOAD
を使用して sickill's answer を使用)することで、アプリケーションによって呼び出された出力関数が何かを出力し、コードを設定して、それらがstderrまたはstdoutで何かを出力するためのものかどうかに基づく前景色。ただし、これは、Cライブラリおよびアプリケーションから直接呼び出されるwrite(2)
syscallを実行するすべての可能な関数をハイジャックして、stdoutまたはstderr(printf、puts、perror .. 。)、それでも、その動作を変更する可能性があります。
別のアプローチとして、PTRACEトリックをstrace
またはgdb
のように使用して、write(2)
システムコールが呼び出されるたびにフックし、write(2)
はファイル記述子1または2にあります。
しかし、それはかなり大きなことです。
私が今使っているトリックは、LD_PRELOADを使用してstrace
自体をハイジャックして(システムコールの前に自分自身をフックするという汚い仕事をする)、出力カラーを変更するように指示することです。 fd 1または2でwrite(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 dupsのため)新しいfdにstderrを実行して、プロンプトとエコーを表示します)。
予想外のアプリケーション(色を使用するアプリケーションなど)でも、驚くほどうまく機能するようです。
着色モードは、端末と見なされるstrace
のstderrに出力されます。アプリケーションがstdoutまたはstderrをリダイレクトする場合、ハイジャックされたstraceは、ターミナルにカラーエスケープシーケンスを書き込み続けます。
このソリューションには制限があります。
strace
に固有の問題:パフォーマンスの問題、その中でstrace
やgdb
などの他のPTRACEコマンドを実行できない、またはsetuid/setgidの問題write
sに基づいて色分けされています。たとえば、sh -c 'echo error >&2'
では、error
はそれをitsstdoutに出力するため、echo
は緑色になります。 (shはshのstderrにリダイレクトされますが、straceが見るすべてはwrite(1, "error\n", 6)
です)。そしてsh -c 'seq 1000000 | wc'
では、seq
はitsstdoutに対してたくさんまたはwrite
sを行うので、ラッパーはたくさんの(見えない)エスケープシーケンスを端末に出力することになります。ここに私がしばらく前にやった概念の証明があります。
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
}