Usuwanie znaków kontrolnych (w tym kodów / kolorów konsoli) z danych wyjściowych skryptu

68

Mogę użyć polecenia „skrypt”, aby nagrać sesję interaktywną w wierszu polecenia. Obejmuje to jednak wszystkie znaki kontrolne i kody kolorów. Mogę usunąć znaki kontrolne (np. Backspace) za pomocą „col -b”, ale nie mogę znaleźć prostego sposobu na usunięcie kodów kolorów.

Zauważ, że chcę używać wiersza poleceń w normalny sposób, więc nie chcę tam wyłączać kolorów - chcę tylko usunąć je z wyników skryptu. Wiem też, że mogę się pobawić i spróbować znaleźć wyrażenie regularne, aby to naprawić, ale mam nadzieję, że istnieje prostsze (i bardziej niezawodne - co, jeśli istnieje kod, o którym nie wiem, kiedy opracowuję wyrażenie regularne?).

Aby pokazać problem:

spl62 tmp: skrypt
Skrypt uruchomiony, plik jest maszynopisem
spl62 lepl: ls
add-licence.sed build-example.sh commit-test push-docs.sh
add-licence.sh build.sh delete-licence.sed setup.py
asn build-test.sh delete-licence.sh src
build-doc.sh clean doc-src test.ini
spl62 lepl: exit
Skrypt wykonany, plik jest maszynopisem
spl62 tmp: cat -v maszynopis
Skrypt został uruchomiony w czwartek 09 czerwca 2011 09:47:27 AM CLT
spl62 lepl: ls ^ M
^ [[0m ^ [[00madd-licence.sed ^ [[0m ^ [[00; 32mbuild-example.sh ^ [[0m ^ [[00m test komendowy ^ [[0m ^ [[00; 32mpush-docs.sh] ^ [[0m ^ M
^ [[00; 32madd-licence.sh ^ [[0m ^ [[00; 32mbuild.sh ^ [[0m ^ [[00mdelete-licence.sed ^] [[0m ^ [[00msetup.py ^ [[0m ^ M
^ [[01; 34masn ^ [[0m ^ [[00; 32mbuild-test.sh ^ [[0m ^ [[00; 32mdelete-licence.sh ^] [[0m ^ [[01; 34msrc ^ [[0m ^ M
^ [[00; 32mbuild-doc.sh ^ [[0m ^ [[00; 32mclean ^ [[0m ^ [[01; 34mdoc-src ^] [[0m ^ [[00mtest.ini ^ [[0m ^ M
spl62 lepl: exit ^ M

Skrypt wykonany w czwartek 09 czerwca 2011 09:47:29 AM CLT
spl62 tmp: col -b <maszynopis 
Skrypt został uruchomiony w czwartek 09 czerwca 2011 09:47:27 AM CLT
spl62 lepl: ls
0m00madd-licence.sed0m 00; 32mbuild-example.sh0m 00m commit-test0m 00; 32mpush-docs.sh0m
00; 32madd-licence.sh0m 00; 32mbuild.sh0m 00mdelete-licence.sed0m 00msetup.py0m
01; 34masn0m 00; 32mbuild-test.sh0m 00; 32mdelete-licence.sh0m 01; 34msrc0m
00; 32mbuild-doc.sh0m 00; 32mclean0m 01; 34mdoc-src0m 00mtest.ini0m
spl62 lepl: exit

Skrypt wykonany w czwartek 09 czerwca 2011 09:47:29 AM CLT
Andrzej Cooke
źródło

Odpowiedzi:

57

Poniższy skrypt powinien odfiltrować wszystkie sekwencje kontrolne ANSI / VT100 / xterm dla (na podstawie ctlseqs ). Minimalnie przetestowane, zgłoś wszelkie niedopasowania lub przeregulowania.

#!/usr/bin/env perl
## uncolor — remove terminal escape sequences such as color changes
while (<>) {
    s/ \e[ #%()*+\-.\/]. |
       \e\[ [ -?]* [@-~] | # CSI ... Cmd
       \e\] .*? (?:\e\\|[\a\x9c]) | # OSC ... (ST|BEL)
       \e[P^_] .*? (?:\e\\|\x9c) | # (DCS|PM|APC) ... ST
       \e. //xg;
    print;
}

Znane problemy:

  • Nie narzeka na zniekształcone sekwencje. Nie do tego służy ten skrypt.
  • Argumenty zawierające wiele wierszy do DCS / PM / APC / OSC nie są obsługiwane.
  • Bajty z zakresu 128–159 mogą być analizowane jako znaki kontrolne, chociaż jest to rzadko używane. Oto wersja, która analizuje znaki sterujące spoza ASCII (spowoduje to zniekształcenie tekstu spoza ASCII w niektórych kodowaniach, w tym UTF-8).
#!/usr/bin/env perl
## uncolor — remove terminal escape sequences such as color changes
while (<>) {
    s/ \e[ #%()*+\-.\/]. |
       (?:\e\[|\x9b) [ -?]* [@-~] | # CSI ... Cmd
       (?:\e\]|\x9d) .*? (?:\e\\|[\a\x9c]) | # OSC ... (ST|BEL)
       (?:\e[P^_]|[\x90\x9e\x9f]) .*? (?:\e\\|\x9c) | # (DCS|PM|APC) ... ST
       \e.|[\x80-\x9f] //xg;
    print;
}
Gilles
źródło
dzięki obu odpowiedziom. czułem, że powinienem zrobić coś jako dobrą odpowiedź, chociaż oba dają wyrażenia regularne, których chciałem uniknąć. wybrałem ten, ponieważ zawiera odniesienie do formatu.
andrew cooke
@andrew: Moje wyrażenie regularne jest na tyle elastyczne, że spodziewam się, że będzie działać z niemal każdym terminalem już istniejącym i prawdopodobnie z każdym terminalem jutrzejszym. Nie testowałem tego zbyt wiele, więc mogą występować błędy, ale podejście jest rozsądne, ponieważ sekwencje kontrolne są zgodne z kilkoma ogólnymi wzorami.
Gilles
proszę podać, jak korzystać z tego skryptu. czy wymaga wprowadzania rur? lub argumenty pozycyjne?
Trevor Boyd Smith
@TrevorBoydSmith Albo będzie działać na dane wejściowe, a dane wyjściowe są zawsze na standardowym wyjściu, podobnie jak typowe narzędzia tekstowe.
Gilles
To zmienia znaki wielobajtowe, takie jak ☺ (\ xe2 \ x98 \ xba). Klauzula [\ x80- \ x9f] usuwa środkowy bajt.
Jeffrey
31

Aktualizacja odpowiedzi Gillesa, aby usunąć również znaki powrotu karetki i wyczyścić poprzednie znaki, które były dla mnie ważne dla maszynopisu wygenerowanego w Cygwin:

#!/usr/bin/perl
while (<>) {
    s/ \e[ #%()*+\-.\/]. |
       \r | # Remove extra carriage returns also
       (?:\e\[|\x9b) [ -?]* [@-~] | # CSI ... Cmd
       (?:\e\]|\x9d) .*? (?:\e\\|[\a\x9c]) | # OSC ... (ST|BEL)
       (?:\e[P^_]|[\x90\x9e\x9f]) .*? (?:\e\\|\x9c) | # (DCS|PM|APC) ... ST
       \e.|[\x80-\x9f] //xg;
       1 while s/[^\b][\b]//g;  # remove all non-backspace followed by backspace
    print;
}
dewtell
źródło
+1 Już pisałem post z tym samym pytaniem, co OP, gdy lubiłem tę wiadomość w twoim skrypcie i @Gilles. +1 dla was
obojga
10

Chciałbym użyć sedw tym przypadku.

zrobić:

cat -v typescript | sed -e "s/\x1b\[.\{1,5\}m//g"

sed -e "s / search / replace / g" jest standardową rzeczą. Wyrażenie regularne jest wyjaśnione jak poniżej:

\x1bdopasowanie Escape poprzedzające kod koloru \[odpowiada pierwszemu otwartemu nawiasowi .\{1,5\}odpowiada od 1 do 5 dowolnego pojedynczego znaku. Muszą \kręcone szelki, aby powstrzymać muszlę przed nimi. mostatni znak w wyrażeniu regularnym - zwykle śledzi kod koloru. //pusty ciąg znaków na co zastąpić wszystko. gdopasuj to wiele razy w linii.

Glorytoad
źródło
3
Ten wyrażenie regularne za dużo usuwa ( foo\e[1m(1m = {staje się foo = {zamiast foo(m = {), zastępowanie .przez [0-9;]jest bardziej dokładne.
Lekensteyn,
Wymienić .\{1,5\}z [^m]\{1,5\}tego - ale również pamiętać, że nawet wtedy jeszcze tylko usuwa „grafika wydania” kody (te, które kończą się m) - w zasadzie kolorów, do tyłu, pogrubienie i kursywa Styl (o ile dotyczy).
Hannu,
To nie usuwa \x1b(B(zawarte w wydruku koloru rdzy)
ideasman42
1
Dlaczego tak jest, \x1ba nie \033?
atripes
Może to być \u001bzamiast\x1b
yunzen
9
cat typescript | perl -pe 's/\e([^\[\]]|\[.*?[a-zA-Z]|\].*?\a)//g' | col -b > typescript-processed
Peter Nore
źródło
6
# The "sed -r" trick does not work on every Linux, I still dunno why:
DECOLORIZE='eval sed "s,${END}\[[0-9;]*[m|K],,g"'

=> jak korzystać:

<commands that type colored output> | ${DECOLORIZE}

testowane na: - AIX 5.x / 6.1 / 7.1 - Linux Mandrake / Mandriva / SLES / Fedora - SunOS

padlinożerca
źródło
3

Rozwiązałem problem, uruchamiając scriptreplayekran i zrzucając bufor przewijania do pliku.

Poniższy skrypt oczekiwań robi to za Ciebie.

Został przetestowany dla plików logów zawierających do 250 000 linii. W katalogu roboczym potrzebujesz swojego dziennika skryptów, pliku o nazwie „czas” z 10.000.000 razy większą niż linia „1 10” oraz skryptu. Potrzebuję nazwę twojego pliku skryptu jako argument wiersza poleceń, jak ./name_of_script name_of_scriptlog.

#!/usr/bin/expect -f 

set logfile [lindex $argv 0]

if {$logfile == ""} {puts "Usage: ./script_to_readable.exp \$logfile."; exit}

set timestamp [clock format [clock sec] -format %Y-%m-%d,%H:%M:%S]
set pwd [exec pwd]
if {! [file exists ${pwd}/time]} {puts "ERROR: time file not found.\nYou need a file named time with 10.000.000 times the line \"1 10\" in the working directory for this script to work. Please provide it."; exit}
set wc [exec cat ${pwd}/$logfile | wc -l]
set height [ expr "$wc" + "100" ]
system cp $logfile ${logfile}.tmp
system echo $timestamp >> ${logfile}.tmp
set timeout -1
spawn screen -h $height -S $timestamp 
send "scriptreplay -t time -s ${logfile}.tmp 100000 2>/dev/null\r"
expect ${timestamp} 
send "\x01:hardcopy -h readablelog.${timestamp}\r"

send "exit\r"

system sed '/^$/d' readablelog.$timestamp >> readablelog2.$timestamp
system head -n-2 readablelog2.$timestamp >> ${logfile}.readable.$timestamp
system rm -f readablelog.$timestamp readablelog2.$timestamp ${logfile}.tmp

Plik czasu może zostać wygenerowany przez

for i in $(seq 1 10000000); do echo "1 10" >> time; done
hnkchnsk
źródło
Polecenie generowania pliku czasu generowało 100% użycia procesora przez kilka minut, a po jego zakończeniu zużycie pamięci wyniosło 100%, a uruchomienie polecenia spowodowało „rozwidlenie: nie można przydzielić pamięci”. I tak naprawdę to nie działało zgodnie z oczekiwaniami.
barteks2x
Istnieje znacznie łatwiejszy sposób na wygenerowanie pliku czasowego. Pola są „ delay blocksize”, więc nie ma powodu, aby po prostu nie „ 0 <entirefile>” i zrzucić wszystkiego bez zwłoki. Możesz to zrobić, biorąc rozmiar skryptu minus pierwszy wiersz ( tail -n +2 typescript|wc -c) i utwórz plik pomiaru czasu za pomocą echo "0 "`tail -n +2 typescript|wc -c` > timing. Będzie to w zasadzie natychmiastowe i scriptreplayodtworzy cały skrypt z największą możliwą prędkością.
FeRD
1

Znalazłem to pytanie, szukając rozwiązania tego samego problemu. Trochę więcej kopie i znalazłem ten skrypt w Live Journal pod tym linkiem. Pracowałem dla siebie idealnie. Jest to również bardzo dobry opis tego problemu i działania rozwiązania. Zdecydowanie warte przeczytania. http://jdimpson.livejournal.com/7040.html

#!/usr/bin/perl -wp

# clean up control characters and other non-text detritus that shows up 
# when you run the "script" command.

BEGIN {
# xterm titlebar escape sequence
$xtermesc = "\x1b\x5d\x30\x3b";

# the occurence of a backspace event (e.g. cntrl H, cntrol W, or cntrl U)
$backspaceevent = "\x1b\\\x5b\x4b"; # note escaping of third character

# ANSI color escape sequence
$ansiesc = qr/\x1b\[[\d;]*?m/;

# technically, this is arrow-right. For some reason, being used against
# very long backspace jobs. I don't fully understand this, as evidenced
# by the fact that is off by one sometimes.
$bizarrebs = qr/\x1b\[C/;

# used as part of the xterm titlebar mechanism, or when
# a bell sounds, which might happen when you backspace too much.
$bell = "\x07"; # could use \a

$cr = "\x0d"; # could use \r

$backspace = "\x08"; # could use \b
}

s/$xtermesc.+?$bell//g;
s/[$cr$bell]//g;
s/${backspaceevent}//g;
s/$ansiesc//g;
while (s/(.)(?=$backspace)//) { s/$backspace//; } # frickin' sweet 
# For every ^H delete the character immediately left of it, then delete the ^H.
# Perl's RE's aren't R, so I wonder if I could do this in one expression.
while (s/(..)(?=$bizarrebs)//) { s/$bizarrebs//; }
SammerV
źródło
1

Wolałbym używać specjalistycznych narzędzi do konwersji danych wyjściowych skryptu na zwykły tekst, który jest stale obsługiwany i dobrze testowany, zamiast niestandardowych wyrażeń regularnych. To dla mnie zadziałało:

$ cat typescript | ansi2txt | col -bp > typescript.txt.bp    
$ cat -v typescript.txt.bp

polecenie skryptu jest przechwytywane do pliku maszynopisu ansi2txt - konwertuje kod ansi ze znakami zmiany znaczenia, takimi jak kody kolorów, spacje itp., na zwykły tekst, jednak zauważyłem, że kilka znaków ucieczki wciąż pozostaje. col -bp - całkowicie je usunął.

Przetestowałem to na najnowszej dyskotece Ubuntu i działa.

Dmytro Brazhnyk
źródło
1

W pakiecie na Ubuntu znajduje się ansi2txtpolecenie colorized-logs. Ładnie usuwa kody kolorów ANSI, ale nie radzi sobie z takimi rzeczami, jak paski postępu wytwarzane przez emitowanie ^Hlub ^Mznaki zastępujące tekst w miejscu. col -bporadzi sobie z nimi , więc dla uzyskania najlepszych rezultatów możesz połączyć oba

cat typescript | ansi2txt | col -b
Marius Gedminas
źródło
0

Przekonałem się, że wystarczyło użyć cat, by zobaczyć dane wyjściowe scriptw terminalu. To nie pomaga, gdy przekierowanie wyjścia do innego pliku, ale nie sprawiają, że wynik czytelny, w przeciwieństwie do cat -v, col -blub edytora tekstu.

Aby wyeliminować kolory lub zapisać wyniki w pliku, ręcznie skopiuj i wklej dane wyjściowe z catedytora tekstu lub do innego catpolecenia, np .:

cat > endResult << END
<paste_copied_text_here>
END
Roger Dueck
źródło
1
czy twój scriptbieg zawiera dane wyjściowe z dołączonymi kodami kolorów, jak w przypadku PO?
Jeff Schaller
Korzystanie catprezentuje oryginalne kolory, które można usunąć ręcznie kopiując i wklejając. Wykorzystany OP cat -vi col -boba przedstawiają kody zamiast poprawnie sformatowanego wyniku końcowego. Zredagowałem swoją odpowiedź.
Roger Dueck
-2

W odpowiedzi na ostatnią odpowiedź, która używa tr i: cntrl: moglibyśmy zrobić

sed "/^[[:cntrl:]]/d" output.txt

Wydaje mi się, że to działa, ponieważ wszystkie linie generowane przez vi zaczynają się od znaku kontrolnego. Zdarza się również, że usuwam puste linie i linie zaczynające się od tabulatora, chociaż to działa w przypadku tego, co robię. Może istnieje sposób na dopasowanie dowolnego znaku kontrolnego oprócz \ n \ m \ t.

Może możemy wyszukać konkretną postać kontrolną i wygląda na to, że wszystkie niepotrzebne linie generowane przez vi zaczynają się od czegoś, co wygląda jak ^ [. hexdump mówi mi, że pierwsza postać to 1b, więc wydaje się, że to też działa

sed "/^\x1b/d" output.txt

Wygląda to podobnie do odpowiedzi zamieszczonej powyżej, ale nie działa poprawnie, ponieważ po uruchomieniu polecenia niektóre niepotrzebne znaki są już dodawane do wiersza poleceń, tak jakby użytkownik je wpisał.

Snaran
źródło
1
Nie ma „ostatniej odpowiedzi”, ponieważ odpowiedzi mogą i zmieniają kolejność. Powinieneś użyć przycisku „Udostępnij” pod odpowiedzią, do której chcesz się odwoływać, i dołączyć to jako link do swojej odpowiedzi. Oczywiście zakładając, że twoja odpowiedź jest czymś więcej niż komentarzem. W tej chwili nie mogę zidentyfikować, do której z kilku odpowiedzi odnosisz się.
roaima
1
„Może moglibyśmy zrobić ...” Tak, mógł to zrobić - ale byłoby usunąć każdy wiersz , który rozpoczyna się od znaku sterującego . Na przykład na wyjściu ls --color(jak pokazano w pytaniu), rozwiązanie usunie prawie każdy wiersz zawierający informacje. Niedobrze. Ale dzięki za pominięcie bezużytecznego użycia cat. :-) ⁠
G-Man
Czy istnieje sposób na utworzenie klasy znaków, która jest: iscntrl: ale nie: isspace :? Może jakaś składnia taka jak ^ [[: iscntrl:] - [: isspace]]
snaran
-4

tr - tłumaczyć lub usuwać znaki

cat typescript | tr -d [[:cntrl:]]
Kawałek
źródło
Witamy w Unix Stackexchange! Udzielając odpowiedzi, lepiej jest wyjaśnić, DLACZEGO twoja odpowiedź jest jedna.
Stephen Rauch
Zwięzłość jest do przyjęcia, ale lepsze są pełniejsze wyjaśnienia. , również nie do końca rozwiązuje ten problem.
Kusalananda
3
To tak naprawdę nie będzie działać poprawnie, ponieważ nie usunie 01;34mnp. I usunie końca linii newline (\n).
sorontar