Usuwanie kodów kolorów ANSI ze strumienia tekstu

73

Sprawdzanie wyniku z

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";'

w edytorze tekstów (np. vi) pokazuje:

^[[37mABC
^[[0m

Jak usunąć kody kolorów ANSI z pliku wyjściowego? Podejrzewam, że najlepszym sposobem byłoby przepuszczenie danych wyjściowych przez swego rodzaju edytor strumieni.

Poniższe nie działa

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";' | perl -pe 's/\^\[\[37m//g' | perl -pe 's/\^\[\[0m//g'
użytkownik001
źródło
Nie jest to odpowiedź na pytanie, ale możesz także przesyłać dane wyjściowe do morelub less -Rktóre mogą interpretować kody specjalne jako kolory zamiast edytora tekstu.
terdon

Odpowiedzi:

98

Znaki ^[[37mi ^[[0msą częścią sekwencji ucieczkowych ANSI (kody CSI) . Zobacz także te specyfikacje .

Korzystanie z GNU sed

sed 's/\x1b\[[0-9;]*m//g'
  • \x1b(lub \x1B) jest specjalnym znakiem ucieczki
    ( sednie obsługuje alternatyw \ei \033)
  • \[ jest drugim znakiem sekwencji ucieczki
  • [0-9;]* to wyrażenia regularne wartości koloru
  • m jest ostatnim znakiem sekwencji ucieczki

⚠ na MacOS, domyślne sedpolecenie nie obsługuje znaków specjalnych, takich jak \ejak podkreślił SLM i steamer25 w komentarzach. Zamiast gsedtego użyj , że możesz zainstalować za pomocą brew install gnu-sed.

Przykład z linią poleceń OP :   (OP oznacza Plakat oryginalny)

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";' | 
      sed 's/\x1b\[[0-9;]*m//g'

Tom Hale sugeruje usunięcie wszystkich innych sekwencji ucieczki, używając [a-zA-Z]zamiast litery mspecyficznej dla sekwencji ucieczki trybu graficznego (koloru). Ale [a-zA-Z]może być zbyt szeroki i może usunąć zbyt wiele. Michał Faleński i Miguel Mota proponują usunięcie tylko niektórych sekwencji ucieczki za pomocą odpowiednio [mGKH]i [mGKF]. Britton Kerin wskazuje, że Knależy również użyć mdo usunięcia kolorów z gccbłędu / ostrzeżenia (nie zapomnij przekierować gcc 2>&1 | sed...).

sed 's/\x1b\[[0-9;]*m//g'           # Remove color sequences only
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g'    # Remove all escape sequences
sed 's/\x1b\[[0-9;]*[mGKH]//g'      # Remove color and move sequences
sed 's/\x1b\[[0-9;]*[mGKF]//g'      # Remove color and move sequences
Last escape
sequence
character   Purpose
---------   -------------------------------
m           Graphics Rendition Mode (including Color)
G           Horizontal cursor move
K           Horizontal deletion
H           New cursor position
F           Move cursor to previous n lines

Za pomocą perl

Wersja sedzainstalowana w niektórych systemach operacyjnych może być ograniczona (np. MacOS). perlZaletą tego polecenia jest to, że ogólnie łatwiej jest je zainstalować / zaktualizować w większej liczbie systemów operacyjnych. Adam Katz sugeruje użycie \e(takiego samego jak \x1b) w PCRE .

Wybierz wyrażenie regularne w zależności od liczby poleceń, które chcesz filtrować:

perl -pe 's/\e\[[0-9;]*m//g'          # Remove colors only
perl -pe 's/\e\[[0-9;]*[mG]//g'
perl -pe 's/\e\[[0-9;]*[mGKH]//g'
perl -pe 's/\e\[[0-9;]*[a-zA-Z]//g'
perl -pe 's/\e\[[0-9;]*m(?:\e\[K)?//g' # Adam Katz's trick

Przykład z linią poleceń OP:

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";' \
      | perl -pe 's/\e\[[0-9;]*m//g'

Stosowanie

Jak wskazał komentarz Stuarta Cardalla , ten sedwiersz poleceń jest używany w projekcie Ultimate Nginx Bad Bot (1000 gwiazdek) do czyszczenia raportu e-mail ;-)

olibre
źródło
2
Dzięki za sedpolecenie i wyjaśnienie. :)
Redsandro,
2
Niektóre kody kolorów (np. Terminal Linuksa) zawierają prefiks, np. 1;31mWięc lepiej dodaj ;do wyrażenia regularnego: cat colored.log | sed -r 's/\x1b\[[0-9;]*m//g'inaczej nie zostaną usunięte.
Redsandro,
1
świetnie to wykorzystuje w github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/blob/… do czyszczenia raportu e-mail.
Stuart Cardall,
2
Należy pamiętać, że wersja OSX sednie działała z pokazanym przykładem, gsedjednak wersja działa.
slm
2
Więcej kontekstu dla komentarza SLM na temat OSX sed: nie obsługuje znaków kontrolnych takich jak \ x1b. Np . Stackoverflow.com/a/14881851/93345 . Możesz uzyskać polecenie gsed za pośrednictwem brew install gnu-sed.
parowiec25
21

Znalazłem lepsze narzędzie do usuwania sekwencji ucieczki. Sprawdź to:

perl -pe 's/\x1b\[[0-9;]*[mG]//g'

użytkownik204331
źródło
2
Jaka jest poprawa w stosunku do zaakceptowanej odpowiedzi ( superuser.com/a/380778/46794 )?
Blaisorblade 30.09.16
4
@ Blaisorblade Działa na OS X, sed -rale NIE.
BVengerov
10

Co jest wyświetlany jako ^[to nie ^ a [; jest to ESCznak ASCII , utworzony przez Esclub Ctrl[( ^notacja oznacza klawisz Ctrl).

ESCma wartość szesnastkową 0x1B lub ósemkową 033, więc musisz użyć \x1Blub \033w wyrażeniach regularnych :

perl -pe 's/\033\[37m//g; s/\033[0m//g'

perl -pe 's/\033\[\d*(;\d*)*m//g'
grawitacja
źródło
6

Jeśli wolisz coś prostego, możesz użyć modułu strip-ansi ( wymagany Node.js ):

$ npm install --global strip-ansi-cli

Następnie użyj go w następujący sposób:

$ strip-ansi < colors.o

Lub po prostu podaj ciąg:

$ strip-ansi '^[[37mABC^[[0m'
Sindre Sorhus
źródło
To bezużyteczne użycie cat( UUOC ) - powinno być możliwe zrobienie strip-ansi colors.oprzynajmniej strip-ansi < colors.o.
Scott
1
@Scott Oczywiście, możesz to zrobić strip-ansi < colors.o, ale z doświadczenia ludzie są bardziej zaznajomieni z rurociągami. Zaktualizowałem odpowiedź.
Sindre Sorhus
dobre proste rozwiązanie
Penghe Geng
2

Pytanie „odpowiedziano” nie działało dla mnie, dlatego stworzyłem to wyrażenie regularne, aby usunąć sekwencje specjalne utworzone przez moduł perl Term :: ANSIColor.

cat colors.o | perl -pe 's/\x1b\[[^m]+m//g;

Wyrażenie regularne Grawity powinno działać poprawnie, ale użycie + wydaje się również działać dobrze.

castl3bravo
źródło
4
(1) Co masz na myśli The "answered" question? Masz na myśli zaakceptowaną odpowiedź? (2) To polecenie nie działa - nawet się nie wykonuje - ponieważ ma niedopasowaną (niezrównoważoną) ofertę. (3) To bezużyteczne użycie cat( UUOC ) - powinno być możliwe . (4) Kto powiedział coś o kodach znajdujących się w pliku? perl -pe command colors.o.o
Scott
2

Uważam, że jest to wiarygodne usunięcie wszystkich sekwencji ucieczki ANSI :

perl -pe '
  s/\e\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]//g;
  s/\e[PX^_].*?\e\\//g;
  s/\e\][^\a]*(?:\a|\e\\)//g;
  s/\e[\[\]A-Z\\^_@]//g;'

(Należy pamiętać, że Perl, podobnie jak wiele innych języków (ale nie sed), przyjmuje \ejako znak ucieczki Esc, \x1blub \033za pomocą kodu, jak pokazano na terminalach ^[. Używam go tutaj, bo wydaje się bardziej intuicyjne.)

To polecenie perla, które możesz uruchomić wszystkie w jednym wierszu, jeśli wolisz, zawiera cztery zastępstwa:

Pierwszy dotyczy sekwencji CSI (sekwencji kodu ucieczki rozpoczynających się od „Control Sequence Introducer” z Esc[, który obejmuje znacznie więcej niż sekwencje Select Graphic Rendition, które składają się z kodów kolorów i innych dekoracji tekstowych).

Druga zamiana usuwa pozostałe sekwencje zawierające końcowe znaki i kończy się na ST (String Terminator, Esc\). Trzecia wymiana to samo, ale również pozwala na polecenie systemu operacyjnego sekwencje do końca z BEL ( \x07, \007często \a).

Czwarta zamiana usuwa pozostałe ucieczki.

Rozważ także usunięcie innych znaków ASCII o zerowej szerokości, takich jak BEL i innych bardziej niejasnych znaków kontrolnych C0 i C1 . Używam s/[\x00-\x1f\x7f-\x9f\xad]+//g, w tym także Usuń i Łagodny łącznik . Wyklucza to kodowane wyżej znaki Unicode o zerowej szerokości, ale uważam, że jest to wyczerpujące dla ASCII (Unicode \x00- \xff). Jeśli to zrobisz, usuń je na końcu, ponieważ mogą być zaangażowane w dłuższe sekwencje.

Adam Katz
źródło
1

„tput sgr0” pozostawił ten znak kontrolny ^ (B ^ [
Oto zmodyfikowana wersja, aby się tym zająć.

perl -pe 's/\e[\[\(][0-9;]*[mGKFB]//g' logfile.log
GustafAnkarloo
źródło
Dzięki za to ... to pomogło mi pozbyć się tego tput sgr0, czego inne rozwiązania nigdy nie wydają się być w stanie się pozbyć.
TxAG98
0

Miałem podobny problem z usuwaniem postaci dodawanych z kolekcjonowania interaktywnego górnego wyjścia za pomocą szpachli, co pomogło:

cat putty1.log | perl -pe 's/\x1b.*?[mGKH]//g'
Michał Faleński
źródło
3
To bezużyteczne użycie cat( UUOC ) - powinno być możliwe . perl -pe command putty1.log
Scott
0

To działało dla mnie (testowane na Mac OS X)

perl -pe 's/\[[0-9;]*[mGKF]//g'
Miguel Mota
źródło