色によるコマンド出力のフィルタリング

色によるコマンド出力のフィルタリング

出力をフィルタリングする方法を提供しないユーティリティを実行しています。出力テキストには、特定の機能が失敗したことを示す内容はありませんが、赤で表示されます。出力が長すぎて最後にいくつかのエラーを報告すると、常にスクロールしてエラーが発生した出力を表示できません。

赤ではなくテキストをフィルタリングする方法は?

擬似コード:

dolongtask | grep -color red

編集する

このコマンドは、フィルタリングできる必要がある他の色も出力します。出るすべてのテキストいいえ赤。テキストの色も複数行です。

答え1

色の切り替えは次のように行われます。エスケープシーケンステキストに含まれています。常に手順の問題ANSIエスケープシーケンス、ほとんどすべての端末が現在これをサポートしているからです。

前景色を赤に切り替えるエスケープシーケンスでは、エスケープ文字が指定され\e[31mます\e(033 8進数、1b 16進数、ESCとも呼ばれる、^[およびその他のさまざまな名前)。 30〜39の範囲の数字は前景色を設定し、他の数字は異なる属性を設定します。\e[0mすべての属性をデフォルト値にリセットします。cat -vプログラムが印刷する内容を確認するために実行すると、\e[0;31mすべてのプロパティを最初にリセットしたり、イタリック体をオンに\e[3;31するなどのいくつかのバリエーションを使用できます(多くの端末ではサポートされていません)。

ksh、bash、またはzshでは、引用符内でバックスラッシュエスケープを有効にして、入力を介してエスケープされた文字を取得$'…'できます。$'\e'に渡すバックスラッシュを2倍にする必要がありますgrep。では、リテラルエスケープ文字を/bin/sh使用または入力できます。"$(printf \\e)"

GNUgrep -oオプションを使用して、次のコードスニペットはエスケープシーケンスで始まり、同じ行で\e[31m終わる\e[0mか、含まれているエスケープシーケンスを含まないと仮定して赤いテキストをフィルタリングします。\e[30m

grep -Eo $'\e\\[31m[^\e]*\e\\[[03]?m'

次のawkコードスニペットは、複数行の場合でも赤いテキストを抽出します。

awk -v RS='\033' '
    match($0, /^\[[0-9;]*m/) {
        color = ";" substr($0, 2, RLENGTH-2) ";";
        $0 = substr($0, RLENGTH+1);
        gsub(/(^|;)0*[^03;][0-9]*($|;)/, ";", color);
        red = (color ~ /1;*$/)
    }
    red'

これは色の変更を維持するコマンドのバリエーションで、複数の色(ここでは赤とマゼンタ)をフィルタリングしたい場合に便利です。

awk -v RS='\033' '
    match($0, /^\[[0-9;]*m/) {
        color = ";" substr($0, 2, RLENGTH-2) ";";
        printf "\033%s", substr($0, 1, RLENGTH);
        $0 = substr($0, RLENGTH+1);
        gsub(/(^|;)0*[^03;][0-9]*($|;)/, ";", color);
        desired = (color ~ /[15];*$/)
    }
    desired'

答え2

grepを使用して制御文字を見つけることができ、その一部は端末にきれいな色を表示するのに役立ちます。

dolongtask | grep '[[:cntrl:]]'

たとえば、これはgrepに赤い「test」と表示され、制御文字で囲まれているのでこれを見つけます。

$ echo -e '\033[00;31mtest\033[00m' | grep --color=none '[[:cntrl:]]'
test     <-- in red

--color=nonegrepが一致する出力に独自の色を適用せずに、シェルが制御文字を解釈できるように行全体を忠実に印刷するようにするためです。

関連情報