Filtruj wyjście polecenia według koloru

13

Korzystam z narzędzia, które nie oferuje sposobu filtrowania danych wyjściowych. Nic w tekście wyniku nie wskazuje, że dana funkcja nie powiodła się, ale jest wyświetlana na czerwono. Dane wyjściowe są tak długie, że pod koniec zgłaszania niektórych błędów nie zawsze mogę przewinąć, aby zobaczyć dane wyjściowe, w których wystąpił błąd.

Jak mogę odfiltrować tekst inny niż czerwony?

pseudo kod:

dolongtask | grep -color red

Edytować

Polecenie wyświetla inne kolory, jak również i muszę być w stanie filtrować się cały tekst, który nie jest czerwony. Również kolorowanie tekstu jest wielowierszowe.

km6zla
źródło
1
Przepraszam za pytanie oczywiste - ale wszystkie dane wyjściowe są włączone >&1? To znaczy, czerwone rzeczy nie znikają, jeśli ty 2>/dev/null, prawda?
mikeserv

Odpowiedzi:

15

Zmiana koloru odbywa się poprzez sekwencje specjalne osadzone w tekście. Niezmiennie programy emitują sekwencje specjalne ANSI , ponieważ to właśnie obsługują obecnie wszystkie terminale.

Sekwencją zmiany znaczenia, która zmienia kolor pierwszego planu na czerwony, jest \e[31m, gdzie \eoznacza znak zmiany znaczenia (ósemkowy 033, szesnastkowy 1b, znany również jako ESC ^[i różne inne oznaczenia). Liczby z zakresu 30–39 określają kolor pierwszego planu; inne liczby ustawiają różne atrybuty. \e[0mresetuje wszystkie atrybuty do ich wartości domyślnej. Uruchom, cat -vaby sprawdzić, co program drukuje, może użyć jakiegoś wariantu, na przykład \e[0;31mnajpierw zresetować wszystkie atrybuty lub \e[3;31włączyć kursywę (które nie obsługuje wielu terminali).

W ksh, bash lub zsh możesz użyć, $'…'aby włączyć $'\e'znaki odwrotnego ukośnika w cudzysłowach, co pozwala pisać, aby uzyskać znak zmiany znaczenia. Pamiętaj, że będziesz musiał podwoić dowolny ukośnik odwrotny, który chcesz przekazać grep. W polu /bin/shmożna użyć "$(printf \\e)"lub wpisać dosłowny znak zmiany znaczenia.

W przypadku grep -oopcji GNU poniższy fragment kodu filtruje czerwony tekst, zakładając, że zaczyna się on sekwencją zmiany znaczenia \e[31m, kończy na jednej \e[0mlub \e[30mw tej samej linii i nie zawiera osadzonej sekwencji zmiany znaczenia.

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

Poniższy awkfragment wyodrębnia czerwony tekst, nawet jeśli jest wielowierszowy.

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'

Oto odmiana, która zachowuje polecenia zmieniające kolory, co może być przydatne, jeśli filtrujesz wiele kolorów (tutaj czerwony i magenta).

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'
Gilles „SO- przestań być zły”
źródło
Rozwiązanie awk działało dla mnie. Jakiś sposób na zachowanie koloru na wydruku?
km6zla
@ ogc-nick Chcesz całkowicie czerwony wynik? printf '\e[31m'; awk …; printf '\e[0m'
Gilles „SO- przestań być zły”
Tylko dla dowolnego koloru, który filtruję, aby zachować na wydruku.
km6zla
@ ogc-nick Zobacz moją edycję.
Gilles „SO- przestań być zły”
6

Możesz mieć wygląd grep dla znaków kontrolnych, z których niektóre są odpowiedzialne za tworzenie ładnych kolorów na terminalu.

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

Na przykład, to echo czerwonego „testu” na grep, który stwierdza, że ​​jest otoczony przez znaki kontrolne:

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

Ma --color=noneto na celu upewnienie się, że grep nie stosuje własnej kolorystyki do dopasowanego wyjścia, ale wiernie drukuje całą linię, aby znaki kontrolne były interpretowane przez powłokę.

savanto
źródło
Ładny. Zastanawiam się, czy można pójść dalej i zrobić coś takiego grep -E $'\033\[0?[01];31m.+?\033\[0?0m'lub grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'przetestować konkretnie na czerwony?
steeldriver
Zacząłem wymieniać wyrażenia regularne takie jak te, które sugerujesz, ale zanim zdołałem je uruchomić, natknąłem się na to [[:cntrl:]]. Przetestowałem twój i działają dla mnie, tj. dopasowywanie czerwonego i nie pasowanie do innych kolorów.
savanto
Działa świetnie, ale pasuje do dowolnego koloru. Nie wspomniałem o tym w pytaniu, ale wyświetlanych jest również wiele innych kolorów i chcę tylko zobaczyć czerwone rzeczy. +1 za prosty i działający kod.
km6zla,