Ausgabe des Befehls nach Farbe filtern


13

Ich verwende ein Dienstprogramm, das keine Möglichkeit zum Filtern der Ausgabe bietet. Nichts im Text der Ausgabe zeigt an, dass eine bestimmte Funktion fehlgeschlagen ist, sie wird jedoch in rot angezeigt. Die Ausgabe ist so lang, dass ich am Ende, wenn einige Fehler gemeldet werden, nicht immer einen Bildlauf durchführen kann, um die Ausgabe zu sehen, bei der der Fehler aufgetreten ist.

Wie kann ich nicht roten Text herausfiltern?

Pseudocode:

dolongtask | grep -color red

Bearbeiten

Der Befehl gibt auch andere Farben aus, und ich muss in der Lage sein , den gesamten Text herauszufiltern , der nicht rot ist. Auch die Textfarbe ist mehrzeilig.


1
Ich entschuldige mich für die offensichtliche Frage - aber alle Ausgaben sind eingeschaltet >&1? Ich meine, das rote Zeug verschwindet nicht 2>/dev/null, oder?
mikeserv

Antworten:


15

Das Umschalten der Farbe erfolgt über im Text eingebettete Escape-Sequenzen . Programme geben ausnahmslos ANSI-Escape-Sequenzen aus , da dies heutzutage von praktisch allen Terminals unterstützt wird.

Die Escape - Sequenz der Vordergrundfarbe auf Rot zu schalten ist \e[31m, in dem \eein Escape - Zeichen bezeichnet (Oktal 033, hexadezimal 1b, die auch als ESC bekannt, ^[und verschiedene andere Bezeichnungen). Zahlen zwischen 30 und 39 legen die Vordergrundfarbe fest. andere Zahlen setzen andere Attribute.\e[0mSetzt alle Attribute auf ihren Standardwert zurück. Führen cat -vSie den Befehl aus, um zu überprüfen, was das Programm druckt. Möglicherweise wird eine Variante verwendet, \e[0;31mum zuerst alle Attribute zurückzusetzen oder \e[3;31um auch Kursivschrift zu aktivieren (was von vielen Terminals nicht unterstützt wird).

In ksh, bash oder zsh können Sie $'…'Backslash- $'\e'Escape-Zeichen in Anführungszeichen aktivieren , um ein Escape-Zeichen zu erhalten. Beachten Sie, dass Sie dann jeden Backslash verdoppeln müssen, an den Sie übergeben möchtengrep . In /bin/shkönnen Sie "$(printf \\e)"ein Escape-Zeichen verwenden oder eingeben.

Mit der GNU- grep -oOption filtert das folgende Snippet roten Text, sofern er mit der Escape-Sequenz \e[31mbeginnt und mit entweder \e[0moder endet\e[30m in derselben Zeile und keine eingebettete Escape-Sequenz enthält.

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

Folgende awk Snippet extrahiert roten Text, auch wenn er mehrzeilig ist.

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'

In dieser Variante werden die Befehle zum Ändern der Farbe beibehalten. Dies kann hilfreich sein, wenn Sie mehrere Farben (hier Rot und Magenta) filtern.

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'

Die awk-Lösung hat bei mir funktioniert. Gibt es eine Möglichkeit, die Farbe in der Ausgabe beizubehalten?
km6zla

@ ogc-nick Du willst eine rein rote Ausgabe? printf '\e[31m'; awk …; printf '\e[0m'
Gilles 'SO- hör auf böse zu sein'

Nur für welche Farbe ich filtere, um in der Ausgabe erhalten zu bleiben.
km6zla

@ ogc-nick Siehe meine bearbeiten.
Gilles 'SO- hör auf böse zu sein'

6

Sie können nach Steuerzeichen suchen, von denen einige für die hübschen Farben auf dem Terminal verantwortlich sind.

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

Dies gibt beispielsweise einen roten "Test" in "grep" wieder, was daran liegt, dass es von Steuerzeichen umgeben ist:

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

Damit --color=nonesoll nur sichergestellt werden, dass grep nicht seine eigene Farbgebung auf die übereinstimmende Ausgabe anwendet, sondern die gesamte Zeile originalgetreu druckt, sodass Steuerzeichen von der Shell interpretiert werden.


Nett. Ich frage mich, ob man noch weiter gehen und sowas machen grep -E $'\033\[0?[01];31m.+?\033\[0?0m'oder grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'gezielt auf Rot testen könnte?
Steeldriver

Ich fing an, mir reguläre Ausdrücke wie die von Ihnen vorgeschlagenen auszudenken, aber bevor ich sie zum Arbeiten bringen konnte, bin ich darauf gestoßen [[:cntrl:]]. Ich habe deine getestet und sie arbeiten für mich, dh. passend zu rot und nicht passend zu anderen Farben.
Savanto

Funktioniert gut, passt aber zu jeder Farbe. Ich habe es in der Frage nicht erwähnt, aber es werden auch viele andere Farben ausgegeben, und ich möchte nur das rote Zeug sehen. +1 für einfachen und funktionierenden Code.
km6zla
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.