Rimozione dei caratteri di controllo (inclusi i codici / i colori della console) dall'output dello script


68

Posso usare il comando "script" per registrare una sessione interattiva dalla riga di comando. Tuttavia, questo include tutti i caratteri di controllo e i codici colore. Posso rimuovere i caratteri di controllo (come backspace) con "col -b", ma non riesco a trovare un modo semplice per rimuovere i codici colore.

Nota che voglio usare la riga di comando in modo normale, quindi non voglio disabilitare i colori lì - voglio solo rimuoverli dall'output dello script. Inoltre, so che può giocare e provare a trovare un regexp per sistemare le cose, ma spero che ci sia una soluzione più semplice (e più affidabile - cosa succede se c'è un codice che non conosco quando sviluppo la regexp?).

Per mostrare il problema:

spl62 tmp: script
Script avviato, il file è dattiloscritto
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: esci
Script fatto, il file è dattiloscritto
spl62 tmp: dattiloscritto cat -v
Script iniziato il gio 09 giu 2011 09:47:27 AM CLT
spl62 lepl: ls ^ M
^ [[0m ^ [[00madd-licence.sed ^ [[0m ^ [[00; 32mbuild-example.sh ^ [[0m ^ [[00mcommit-test ^ [[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: esci ^ M

Script fatto il gio 09 giu 2011 09:47:29 CLT
spl62 tmp: col -b <dattiloscritto 
Script iniziato il gio 09 giu 2011 09:47:27 AM CLT
spl62 lepl: ls
0m00madd-licence.sed0m 00; 32mbuild-example.sh0m 00mcommit-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: esci

Script fatto il gio 09 giu 2011 09:47:29 CLT

Risposte:


57

Il seguente script dovrebbe filtrare tutte le sequenze di controllo ANSI / VT100 / xterm per (basate su ctlseqs ). Testato minimamente, si prega di segnalare qualsiasi sotto-partita o sovra-partita.

#!/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;
}

Problemi noti:

  • Non si lamenta delle sequenze malformate. Non è questo lo scopo di questo script.
  • Gli argomenti di stringa multilinea su DCS / PM / APC / OSC non sono supportati.
  • I byte nell'intervallo 128–159 possono essere analizzati come caratteri di controllo, anche se raramente vengono utilizzati. Ecco una versione che analizza i caratteri di controllo non ASCII (questo manipolerà il testo non ASCII in alcune codifiche tra cui 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;
}

grazie ad entrambe le risposte. sentivo che avrei dovuto fare qualcosa come una buona risposta, sebbene entrambi dessero regexps, che volevo evitare. scelto questo in quanto fornisce un riferimento per il formato.
Andrew Cooke,

@andrew: Il mio regexp è abbastanza flessibile che mi aspetto che funzioni praticamente con qualsiasi terminale esistente, e probabilmente anche con qualsiasi terminale esistente domani. Non l'ho testato molto, quindi potrebbero esserci dei bug, ma l'approccio è valido poiché le sequenze di controllo seguono alcuni schemi generali.
Gilles 'SO- smetti di essere malvagio' il

si prega di fornire come utilizzare questo script. richiede l'input di pipe? o argomenti posizionali?
Trevor Boyd Smith,

@TrevorBoydSmith Entrambi funzioneranno per l'input e l'output è sempre sull'output standard, come le normali utility di testo.
Gilles 'SO- smetti di essere malvagio' il

In questo modo si mangiano personaggi multibyte come ☺ (\ xe2 \ x98 \ xba). La clausola [\ x80- \ x9f] rimuove il byte centrale.
Jeffrey,

31

Aggiornamento della risposta di Gilles per rimuovere anche i ritorni a capo e cancellare il backspace dei personaggi precedenti, che erano entrambi importanti per me per un dattiloscritto generato su 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;
}

+1 Stavo già scrivendo un post con la stessa domanda dell'OP quando mi piaceva questo messaggio con la tua sceneggiatura e quella di @Gilles. +1 per entrambi
miracle173

10

Vorrei usare sedin questo caso.

fare:

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

sed -e "s / cerca / sostituisci / g" è roba standard. la regex è spiegata come di seguito:

\x1bcorrisponde alla Fuga che precede il codice colore \[corrisponde alla prima parentesi aperta .\{1,5\}corrispondente da 1 a 5 di ogni singolo carattere. Devono \le parentesi graffe per impedire al guscio di rovinarli. multimo carattere in regex - di solito segue il codice colore. //stringa vuota per cosa sostituire tutto. gabbinalo più volte per riga.


3
Questa regex si spoglia troppo ( foo\e[1m(1m = {diventa foo = {invece di foo(m = {), sostituendo .con [0-9;]è più preciso.
Lekensteyn,

Sostituiscilo .\{1,5\}con [^m]\{1,5\}quello - ma nota anche che questo rimuove ancora solo i codici di "rendering grafico" (quelli che terminano con un m) - fondamentalmente stili di colore, reverse, grassetto e corsivo (dove applicabile).
Hannu,

Questo non viene rimosso \x1b(B(incluso nell'output del colore ruggine)
ideasman42

1
Perché è \x1be no \033?
Atripes,

Potrebbe essere \u001binvece di\x1b
yunzen

9
cat typescript | perl -pe 's/\e([^\[\]]|\[.*?[a-zA-Z]|\].*?\a)//g' | col -b > typescript-processed

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"'

=> come usare:

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

testato su: - AIX 5.x / 6.1 / 7.1 - Linux Mandrake / Mandriva / SLES / Fedora - SunOS


3

Ho risolto il problema eseguendo scriptreplayuna schermata e scaricando il buffer di scorrimento su un file.

Il seguente script di attesa fa questo per te.

È stato testato per file di registro con un massimo di 250.000 righe. Nella directory di lavoro è necessario il tuo scriptlog, un file chiamato "time" con 10.000.000 volte la riga "1 10" e lo script. Ho bisogno del nome del tuo file di script come argomento della riga di comando, come ./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

Il file temporale può essere generato da

for i in $(seq 1 10000000); do echo "1 10" >> time; done

Il comando per la generazione del file time ha generato il 100% di utilizzo della CPU per alcuni minuti e dopo aver terminato l'utilizzo della memoria è stato del 100% e l'esecuzione del comando ha comportato "fork: impossibile allocare memoria". E non ha funzionato davvero come previsto.
barteks2x,

C'è un modo molto più semplice per generare il file di temporizzazione. I campi sono " delay blocksize", quindi non c'è motivo di non farlo " 0 <entirefile>" e scaricare l'intera cosa senza indugio. Puoi farlo prendendo la dimensione dello script meno la prima riga ( tail -n +2 typescript|wc -c) e creando il file di timing con echo "0 "`tail -n +2 typescript|wc -c` > timing. Sarà sostanzialmente istantaneo e scriptreplayriprodurrà l'intero script alla massima velocità possibile.
FERD

1

Ho trovato questa domanda mentre cercavo una soluzione allo stesso problema. Un po 'più di ricerca e ho trovato questo script su Live Journal a questo link. Ho lavorato perfettamente per me. È anche un ottimo commento su questo problema e su come funziona la soluzione. Sicuramente merita una lettura. 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//; }

1

Preferirei utilizzare strumenti specializzati per convertire l'output di script in testo semplice, che è costantemente supportato e ben testato, su regexp personalizzato. Quindi questo ha funzionato per me:

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

Il comando script acquisisce nel file dattiloscritto ansi2txt - converte il codice ansi con escape come colorcodes, backspaces ecc. in testo normale, tuttavia ho scoperto che un paio di escape sono ancora rimasti. col -bp - li ha rimossi completamente.

L'ho provato sull'ultima discoteca Ubuntu e funziona.


1

C'è un ansi2txtcomando nel colorized-logspacchetto su Ubuntu. Rimuove bene i codici colore ANSI, ma non si occupa di cose come barre di avanzamento prodotte dall'emissione ^Ho ^Mcaratteri per sovrascrivere il testo in atto. col -bpuò trattare con coloro che , in modo per ottenere i migliori risultati è possibile combinare le due cose

cat typescript | ansi2txt | col -b

0

Ho scoperto che usare solo catera tutto ciò di cui avevo bisogno per visualizzare l'output scriptnel terminale. Questo non aiuta quando reindirizzare l'output in un altro file, ma non rendere il risultato leggibile, a differenza cat -v, col -bo un editor di testo.

Per eliminare i colori o salvare i risultati in un file, copia e incolla manualmente l'output catin un editor di testo o in un altro catcomando, ad esempio:

cat > endResult << END
<paste_copied_text_here>
END

1
la tua scriptcorsa ha incluso l'output con i codici colore allegati, come nel caso dell'OP?
Jeff Schaller

Utilizzando catpresenta i colori originali, che possono essere rimossi mediante copia e incolla manuali. L'OP utilizzato cat -ve col -b, entrambi i quali presentano codici anziché un risultato finale correttamente formattato. Ho modificato la mia risposta.
Roger Dueck,

-2

Seguendo l'ultima risposta che usa tr e: cntrl: forse potremmo farlo

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

Questo sembra funzionare per me perché tutte le righe generate da vi iniziano con un carattere di controllo. Capita anche di eliminare le righe vuote e le righe che iniziano con una scheda, anche se funziona per quello che sto facendo. Forse c'è un modo per abbinare qualsiasi personaggio di controllo tranne \ n \ m \ t.

Forse possiamo cercare il particolare carattere di controllo e sembra che tutte le linee spazzatura generate da vi inizino con quello che sembra ^ [. hexdump mi dice che il primo personaggio è 1b, quindi anche questo sembra funzionare

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

Sembra simile a una risposta pubblicata sopra, ma non funziona correttamente perché dopo aver eseguito il comando, alcuni caratteri spazzatura vengono già aggiunti alla riga di comando come se l'utente li avesse digitati.


1
Non esiste "ultima risposta" in quanto le risposte possono e cambiano l'ordine. È necessario utilizzare il pulsante "condividi" sotto la risposta a cui si desidera fare riferimento e includerlo come collegamento nella risposta. Supponendo che la tua risposta sia sufficiente per essere più che un commento, ovviamente. In questo momento non riesco a identificare quale delle diverse risposte a cui fai riferimento.
roaima,

1
“Potremmo forse fare ...” Sì, abbiamo potuto farlo - ma sarebbe eliminare ogni riga che inizia con un carattere di controllo . Nell'output di, ad esempio, ls --color(come mostrato nella domanda), la soluzione eliminerà quasi ogni riga che contiene informazioni. Non bene. Ma grazie per aver tralasciato l'uso inutile di cat. :-) ⁠
G-Man il

C'è un modo per creare una classe di caratteri che sia: iscntrl: ma non: isspace :? Forse una sintassi come ^ [[: iscntrl:] - [: isspace]]
snaran

-4

tr - tradurre o eliminare caratteri

cat typescript | tr -d [[:cntrl:]]

Benvenuto in Unix Stackexchange! Quando dai una risposta è preferibile dare una spiegazione del PERCHÉ la tua risposta è quella.
Stephen Rauch,


3
Questo in realtà non funzionerà correttamente, in quanto non rimuoverà un 01;34mesempio, e rimuoverà la fine della linea newline (\n).
sorontar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.