Eliminar caracteres de control (incluidos códigos / colores de consola) de la salida del script

68

Puedo usar el comando "script" para grabar una sesión interactiva en la línea de comando. Sin embargo, esto incluye todos los caracteres de control y códigos de color. Puedo eliminar los caracteres de control (como retroceso) con "col -b", pero no puedo encontrar una manera simple de eliminar los códigos de color.

Tenga en cuenta que quiero usar la línea de comandos de la manera normal, así que no quiero deshabilitar los colores allí, solo quiero eliminarlos de la salida del script. Además, sé que puedo jugar e intentar encontrar una expresión regular para arreglar las cosas, pero espero que haya una solución más simple (y más confiable, ¿qué pasa si hay un código que no conozco cuando desarrollo la expresión regular?).

Para mostrar el problema:

spl62 tmp: script
Script iniciado, el archivo es mecanografiado
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: salir
Script hecho, el archivo es mecanografiado
spl62 tmp: mecanografiado cat -v
El guión comenzó el jue 09 jun 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: salir ^ M

Guión hecho el jue 09 jun 2011 09:47:29 AM CLT
spl62 tmp: col -b <mecanografiado 
El guión comenzó el jue 09 jun 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: salir

Guión hecho el jue 09 jun 2011 09:47:29 AM CLT
Andrew Cooke
fuente

Respuestas:

57

El siguiente script debe filtrar todas las secuencias de control ANSI / VT100 / xterm para (basadas en ctlseqs ). Probado mínimamente, por favor informe cualquier sub-coincidencia.

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

Problemas conocidos:

  • No se queja de secuencias malformadas. Para eso no es este script.
  • No se admiten argumentos de cadena de varias líneas para DCS / PM / APC / OSC.
  • Los bytes en el rango de 128-159 pueden analizarse como caracteres de control, aunque esto rara vez se usa. Aquí hay una versión que analiza los caracteres de control no ASCII (esto alterará el texto no ASCII en algunas codificaciones, incluyendo 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 'SO- deja de ser malvado'
fuente
Gracias a ambas respuestas. Sentí que debería hacer algo como una buena respuesta, aunque ambas dan expresiones regulares, que quería evitar. eligió este ya que da una referencia para el formato.
Andrew Cooke
@andrew: Mi expresión regular es lo suficientemente flexible que espero que funcione con casi cualquier terminal existente ahora, y probablemente también con cualquier terminal existente mañana. No lo he probado mucho, por lo que puede haber errores, pero el enfoque es sólido ya que las secuencias de control siguen algunos patrones generales.
Gilles 'SO- deja de ser malvado'
proporcione cómo usar este script. ¿requiere entrada de tubería? o argumentos posicionales?
Trevor Boyd Smith
@TrevorBoydSmith O trabajará para la entrada, y la salida siempre está en la salida estándar, como las utilidades de texto típicas.
Gilles 'SO- deja de ser malvado'
Esto manipula caracteres multibyte como ☺ (\ xe2 \ x98 \ xba). La cláusula [\ x80- \ x9f] elimina el byte medio.
Jeffrey
31

Actualizar la respuesta de Gilles para eliminar también los retornos de carro y borrar espacios anteriores de caracteres anteriores, que fueron importantes para mí para un mecanografiado generado en 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;
}
rocío
fuente
+1 Ya estaba escribiendo una publicación con la misma pregunta que el OP cuando aprecié este mensaje con tu script y el de @Gilles. +1 para los dos
milagro173
10

Lo usaría seden este caso.

hacer:

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

sed -e "s / search / replace / g" es material estándar. La expresión regular se explica a continuación:

\x1bcoincidir con el Escape anterior al código de color \[coincide con el primer paréntesis abierto .\{1,5\}coincide con 1 a 5 de cualquier carácter individual. Tiene que \usar llaves para evitar que la cáscara las destroce. múltimo carácter en expresiones regulares: generalmente sigue el código de color. //cadena vacía para reemplazar todo. gcoincidir varias veces por línea.

Glorytoad
fuente
3
Esta expresión regular se elimina demasiado (se foo\e[1m(1m = {convierte en foo = {lugar de foo(m = {), el reemplazo .por [0-9;]es más preciso.
Lekensteyn
Reemplazar .\{1,5\}con [^m]\{1,5\}para eso - sino que también tenga en cuenta que esto incluso entonces todavía sólo elimina los códigos gráficos de "entregas extraordinarias" (aquellos que terminan en una m) - básicamente de color, revertir, negrita y cursiva estilos (en su caso).
Hannu
Esto no se elimina \x1b(B(incluido en la salida de color
óxido
1
¿Por qué es \x1by no \033?
atripes
Podría ser en \u001blugar de\x1b
yunzen
9
cat typescript | perl -pe 's/\e([^\[\]]|\[.*?[a-zA-Z]|\].*?\a)//g' | col -b > typescript-processed
Peter Nore
fuente
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"'

=> cómo usar:

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

probado en: - AIX 5.x / 6.1 / 7.1 - Linux Mandrake / Mandriva / SLES / Fedora - SunOS

carroñero
fuente
3

Resolví el problema ejecutando scriptreplayen una pantalla y volcando el búfer de desplazamiento a un archivo.

El siguiente script de esperar hace esto por usted.

Se ha probado para archivos de registro con hasta 250,000 líneas. En el directorio de trabajo necesita su registro de script, un archivo llamado "tiempo" con 10.000.000 veces la línea "1 10" y el script. Necesito el nombre de su archivo de script como argumento de línea de comando, como ./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

El archivo de tiempo puede ser generado por

for i in $(seq 1 10000000); do echo "1 10" >> time; done
hnkchnsk
fuente
El comando para generar el archivo de tiempo generó el uso del 100% de la CPU durante unos minutos y después de que terminó, el uso de mi memoria fue del 100% y el comando en ejecución resultó en "fork: no se puede asignar memoria". Y realmente no funcionó como se esperaba.
barteks2x
Hay una manera mucho más fácil de generar el archivo de sincronización. Los campos son " delay blocksize", así que no hay razón para no hacerlo " 0 <entirefile>" y volcar todo sin demora. Puede hacerlo tomando el tamaño del script menos la primera línea ( tail -n +2 typescript|wc -c) y creando el archivo de sincronización con echo "0 "`tail -n +2 typescript|wc -c` > timing. Eso será básicamente instantáneo y scriptreplayreproducirá todo el script a la velocidad más rápida posible.
FeRD
1

Encontré esta pregunta mientras buscaba la solución al mismo problema. Un poco más de excavación y encontré este script en Live Journal en este enlace. Trabajé perfectamente para mí. También es muy bueno escribir sobre este problema y cómo funciona la solución. Definitivamente vale la pena leerlo. 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
fuente
1

Preferiría usar herramientas especializadas para convertir la salida del script en texto plano, que es constantemente compatible y bien probado, sobre expresiones regulares personalizadas. Así que esto funcionó para mí:

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

Capturas de comandos de script en archivos de mecanografiado ansi2txt: convierte el código ansi con escapes como códigos de color, espacios de retroceso, etc. en texto normal, sin embargo, descubrí que aún quedan algunos escapes. col -bp: los eliminó por completo.

He probado esto en la última disco de Ubuntu, y funciona.

Dmytro Brazhnyk
fuente
1

Hay un ansi2txtcomando en el colorized-logspaquete en Ubuntu. Elimina los códigos de color ANSI muy bien, pero no se ocupa de cosas como barras de progreso producidas por la emisión ^Ho ^Mcaracteres para sobrescribir el texto en su lugar. col -bpuede lidiar con ellos , por lo que para obtener los mejores resultados, puede combinar los dos

cat typescript | ansi2txt | col -b
Marius Gedminas
fuente
0

Descubrí que solo usar catera todo lo que necesitaba para ver la salida del scriptterminal. Esto no ayuda al redirigir la salida a otro archivo, pero hace que el resultado legible, a diferencia cat -v, col -bo un editor de texto.

Para eliminar colores o guardar los resultados en un archivo, copie y pegue manualmente la salida caten un editor de texto o en otro catcomando, es decir:

cat > endResult << END
<paste_copied_text_here>
END
Roger Dueck
fuente
1
¿ scriptincluyó su ejecución salida con códigos de color adjuntos, como en el caso del OP?
Jeff Schaller
El uso catpresenta los colores originales, que se pueden eliminar mediante copia y pegado manual. El OP utilizado cat -vy col -b, ambos códigos presentes en lugar de un resultado final con el formato correcto. He editado mi respuesta.
Roger Dueck
-2

Continuando con la última respuesta que usa tr y: cntrl: ¿podríamos hacer

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

Esto parece funcionar para mí porque todas las líneas generadas por vi comienzan con un carácter de control. También elimina líneas en blanco y líneas que comienzan con una pestaña, aunque eso funciona para lo que estoy haciendo. Quizás haya una manera de hacer coincidir cualquier carácter de control, excepto \ n \ m \ t.

Tal vez podamos buscar el carácter de control particular, y parece que todas las líneas basura generadas por vi comienzan con lo que parece ^ [. hexdump me dice que el primer personaje es 1b, por lo que esto parece funcionar también

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

Esto se parece a una respuesta publicada anteriormente, pero no funciona correctamente porque después de ejecutar el comando, algunos caracteres basura ya se han agregado a la línea de comando como si el usuario los hubiera escrito.

Snaran
fuente
1
No hay una "última respuesta", ya que las respuestas pueden y cambian el orden. Debe usar el botón "compartir" debajo de la respuesta a la que desea hacer referencia e incluirlo como un enlace en su respuesta. Asumir que su respuesta es suficiente para ser más que un comentario, por supuesto. En este momento no puedo identificar a cuál de las varias respuestas hace referencia.
roaima
1
"Podríamos hacer ..." Sí, podríamos hacer eso, pero eliminaría cada línea que comience con un carácter de control . En la salida de, por ejemplo, ls --color(como se muestra en la pregunta), su solución eliminará casi todas las líneas que contienen información. No está bien. Pero gracias por dejar de lado el uso inútil de cat. :-) ⁠
G-Man
¿Hay alguna manera de crear una clase de caracteres que sea: iscntrl: pero no: isspace :? Tal vez alguna sintaxis como ^ [[: iscntrl:] - [: isspace]]
snaran
-4

tr - traducir o eliminar caracteres

cat typescript | tr -d [[:cntrl:]]
Pedazo
fuente
¡Bienvenido a Unix Stackexchange! Al dar una respuesta, es preferible dar una explicación de POR QUÉ su respuesta es la correcta.
Stephen Rauch
3
En realidad, esto no funcionará correctamente, ya que no eliminará un, 01;34mpor ejemplo, y eliminará el final de la línea newline (\n).
sorontar