Suppression des caractères de contrôle (y compris les codes de console / couleurs) de la sortie de script


68

Je peux utiliser la commande "script" pour enregistrer une session interactive sur la ligne de commande. Cependant, cela inclut tous les caractères de contrôle et les codes de couleur. Je peux supprimer les caractères de contrôle (comme le retour arrière) avec "col -b", mais je ne trouve pas un moyen simple de supprimer les codes de couleur.

Notez que je souhaite utiliser la ligne de commande de manière normale. Par conséquent, ne souhaitez pas désactiver les couleurs. Je souhaite simplement les supprimer de la sortie du script. Je sais aussi que je peux jouer et essayer de trouver une expression rationnelle pour résoudre le problème, mais j'espère qu'il existe une solution plus simple (et plus fiable - et s'il y avait un code que je ne connaissais pas lorsque je développais l'expression rationnelle?).

Pour montrer le problème:

spl62 tmp: script
Le script a démarré, le fichier est dactylographié
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 nettoie doc-src test.ini
spl62 lepl: sortie
Script terminé, le fichier est dactylographié
spl62 tmp: type de script cat -v
Le script a commencé le jeu. 09 juin 2011 09:47:27 CLT
spl62 lepl: ls ^ M
^ [[0m ^ [[00madd-licence.sed ^ [[0m ^ [[00; 32mbuild-example.sh. ^ [[0m ^ M
^ [[00; 32madd-licence.sh ^ [[0m ^ [[00; 32mbuild.sh ^ [[0m ^ [[00mdelete-licence.sed ^ [[0m ^ [[00msetup.py ^ [[0m ^ M
^ [[01; 34masn ^ [[0m ^ [[00; 32; test dembuild.sh ^ [[0m ^ [[00; 32mdelete-licence.sh. 32mdelete-licence.sh.
^ [[00; 32mbuild-doc.sh ^ [[0m ^ [[00; 32mclean ^ [[0m ^ [[01; 34mdoc-src ^ [^ 0m ^ [[00mtest.ini ^ [[0m ^ M
spl62 lepl: sortie ^ M

Script réalisé le jeu. 09 juin 2011 09:47:29 CLT
spl62 tmp: col -b <typescript 
Le script a commencé le jeu. 09 juin 2011 09:47:27 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: sortie

Script réalisé le jeu. 09 juin 2011 09:47:29 CLT

Réponses:


57

Le script suivant doit filtrer toutes les séquences de contrôle ANSI / VT100 / xterm pour (sur la base de ctlseqs ). Testé au minimum, veuillez signaler toute correspondance insuffisante ou excessive.

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

Problèmes connus:

  • Ne se plaint pas de séquences malformées. Ce n'est pas ce que ce script est pour.
  • Les arguments de chaîne multiligne dans DCS / PM / APC / OSC ne sont pas pris en charge.
  • Les octets compris entre 128 et 159 peuvent être analysés comme des caractères de contrôle, bien que cela soit rarement utilisé. Voici une version qui analyse les caractères de contrôle non-ASCII (cela modifiera le texte non-ASCII dans certains codages, y compris 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;
}

grâce aux deux réponses. Je sentais que je devais faire quelque chose comme une bonne réponse, même si les deux donnent des expressions rationnelles, ce que je voulais éviter. choisi celui-ci car il donne une référence pour le format.
Andrew Cooke

@andrew: Mon expression rationnelle est suffisamment flexible pour pouvoir fonctionner avec pratiquement tous les terminaux existants, et probablement avec tous les terminaux de demain. Je ne l'ai pas beaucoup testé, alors il y a peut-être des bugs, mais l'approche est bonne car les séquences de contrôle suivent quelques modèles généraux.
Gilles 'SO- arrête d'être méchant'

veuillez indiquer comment utiliser ce script. nécessite-t-il une entrée de tuyau? ou des arguments de position?
Trevor Boyd Smith

@TrevorBoydSmith L'un ou l'autre fonctionnera pour l'entrée et la sortie est toujours sur la sortie standard, comme les utilitaires de texte classiques.
Gilles 'SO- arrête d'être méchant'

Cela modifie les caractères multi-octets tels que (\ xe2 \ x98 \ xba). La clause [\ x80- \ x9f] supprime l'octet du milieu.
Jeffrey

31

Mettre à jour la réponse de Gilles pour supprimer également les retours à la ligne et effacer les caractères précédents, ce qui était important pour une police manuscrite générée sur 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 J'écrivais déjà un message avec la même question que l'OP lorsque j'ai associé ce message à votre script et à celui de @Gilles. +1 pour vous deux
miracle173

10

Je voudrais utiliser seddans ce cas.

faire:

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

sed -e "s / search / replace / g" est standard. la regex est expliquée ci-dessous:

\x1bcorrespond à la sortie d'échappement précédant le code de couleur \[correspond à la première tranche ouverte .\{1,5\}correspond à 1 à 5 de n'importe quel caractère. Ayez \les accolades pour empêcher la coquille de les briser. mdernier caractère de regex - traîne généralement le code de couleur. //chaîne vide pour quoi remplacer tout par. gassociez-le plusieurs fois par ligne.


3
Cette expression rationnelle dépouille trop ( foo\e[1m(1m = {devient foo = {au lieu de foo(m = {), le remplacement .par [0-9;]est plus précis.
Lekensteyn

Remplacez .\{1,5\}par [^m]\{1,5\}, mais notez que cela supprime encore les codes de "rendu graphique" (ceux qui se terminent par un m) - essentiellement les styles couleur, inverse, gras et italique (le cas échéant).
Hannu

Cela ne supprime pas \x1b(B(inclus dans la sortie couleur des rouilles)
ideasman42

1
Pourquoi est-ce \x1bet non \033?
arrive

Ce pourrait être \u001bau lieu de\x1b
mardi

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

=> comment utiliser:

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

testé sur: - AIX 5.x / 6.1 / 7.1 - Linux Mandrake / Mandriva / SLES / Fedora - SunOS


3

J'ai résolu le problème en exécutant scriptreplaydans un écran et en vidant la mémoire tampon de défilement dans un fichier.

Le script attendu suivant le fait pour vous.

Il a été testé pour les fichiers journaux contenant jusqu'à 250 000 lignes. Dans le répertoire de travail, vous avez besoin de votre journal de script, un fichier appelé "time" contenant 10 000 000 de fois la ligne "1 10", et du script. J'ai besoin du nom de votre fichier de script comme argument de ligne de commande, comme ./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

Le fichier de temps peut être généré par

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

La commande de génération de fichier de temps a généré une utilisation de 100% de l'UC pendant quelques minutes. Une fois l'utilisation de la mémoire terminée, elle était de 100%. L'exécution de la commande a entraîné "fork: impossible d'allouer de la mémoire". Et cela n'a pas vraiment fonctionné comme prévu.
barteks2x

Il existe un moyen beaucoup plus simple de générer le fichier de chronométrage. Les champs sont " delay blocksize", il n'y a donc aucune raison de ne pas le faire " 0 <entirefile>" et de vider le tout sans délai. Vous pouvez le faire en prenant la taille du script moins la première ligne ( tail -n +2 typescript|wc -c) et créez le fichier de minutage avec echo "0 "`tail -n +2 typescript|wc -c` > timing. Ce sera essentiellement instantané et scriptreplaypermettra de rejouer l'intégralité du script à la vitesse la plus rapide possible.
FeRD

1

Vous avez trouvé cette question en cherchant une solution au même problème. Un peu plus de creuser et trouvé ce script sur Live Journal à ce lien. J'ai parfaitement travaillé pour moi. C'est également une très bonne description de ce problème et du fonctionnement de la solution. Vaut vraiment la peine d'être lu. 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

Je préférerais utiliser des outils spécialisés pour convertir les sorties de script en texte brut, qui est constamment pris en charge et bien testé, par rapport à une expression rationnelle personnalisée. Donc, cela a fonctionné pour moi:

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

La commande de script capture dans un fichier dactylographié ansi2txt - convertit le code ansi avec des échappements tels que les codes de couleur, les backspaces, etc. en texte normal. col -bp - les a complètement supprimés.

J'ai testé cela sur la dernière disco Ubuntu, et ça marche.


1

Il y a une ansi2txtcommande dans le colorized-logspaquet sur Ubuntu. Il supprime les codes de couleur ANSI, mais ne traite pas d'éléments tels que les barres de progression générées par l'émission ^Hou les ^Mcaractères utilisés pour remplacer le texte à la place. col -bpeut traiter avec ceux-ci , donc pour de meilleurs résultats, vous pouvez combiner les deux

cat typescript | ansi2txt | col -b

0

J'ai constaté que cattout ce dont j'avais besoin pour visualiser la sortie du scriptterminal était de l' utiliser . Cela ne permet pas lors de la redirection de la sortie vers un autre fichier, mais ne rend le résultat lisible, à la différence cat -v, col -bou un éditeur de texte.

Pour éliminer les couleurs ou enregistrer les résultats dans un fichier, copiez et collez manuellement la sortie catdans un éditeur de texte ou dans une autre catcommande, par exemple:

cat > endResult << END
<paste_copied_text_here>
END

1
Votre scriptsérie inclut-elle une sortie avec des codes de couleur attachés, comme dans le cas du PO?
Jeff Schaller

Utilisation catprésente les couleurs d'origine, qui peuvent être supprimées par copier-coller manuel. Le PO utilisé cat -vet col -b, qui présentent tous deux des codes plutôt qu'un résultat final correctement formaté. J'ai édité ma réponse.
Roger Dueck

-2

Suite de la dernière réponse qui utilise tr et: cntrl: pourrions-nous peut-être faire

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

Cela semble fonctionner pour moi car toutes les lignes générées par vi commencent par un caractère de contrôle. Il arrive également de supprimer les lignes vides et les lignes commençant par une tabulation, bien que cela fonctionne pour ce que je fais. Il existe peut-être un moyen de faire correspondre tout caractère de contrôle, à l’exception de \ n \ m \ t.

Peut-être que nous pouvons rechercher le caractère de contrôle particulier, et il semble que toutes les lignes d'ordure générées par vi commencent par ce qui ressemble à ^ [. hexdump me dit que le premier caractère est 1b, donc cela semble fonctionner aussi

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

Cela ressemble à une réponse publiée ci-dessus, mais cela ne fonctionne pas correctement car après l'exécution de la commande, certains caractères indésirables sont déjà ajoutés à la ligne de commande, comme si l'utilisateur les avait saisis.


1
Il n'y a pas de "dernière réponse" car les réponses peuvent changer et ne changent pas d'ordre. Vous devez utiliser le bouton "Partager" situé sous la réponse à laquelle vous souhaitez faire référence et l'inclure en tant que lien dans votre réponse. En supposant que votre réponse soit suffisante pour être plus qu'un commentaire, bien sûr. Pour le moment, je ne peux pas identifier laquelle des réponses à laquelle vous faites référence.
Roaima

1
« Pourrions - nous faire peut - être ... » Oui, nous pourrions le faire - mais ce serait supprimer chaque ligne qui commence par un caractère de contrôle . Par exemple, à la sortie de ls --color(comme indiqué dans la question), votre solution supprimera presque toutes les lignes contenant des informations. Pas bon. Mais merci d'avoir laissé de côté l'utilisation inutile de cat. :-) ⁠
G-Man dit 'Réintégrez Monica' le

Est-il possible de créer une classe de caractères qui est: iscntrl: mais pas: isspace :? Peut-être qu'une syntaxe comme ^ [[: iscntrl:] - [: isspace]]
snaran le

-4

tr - traduire ou supprimer des caractères

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

Bienvenue sur Unix Stackexchange! Lorsque vous répondez, il est préférable d' expliquer POURQUOI votre réponse est la bonne.
Stephen Rauch le


3
Cela ne fonctionnera pas correctement car cela ne supprimera pas un 01;34mexemple et supprimera la fin de la ligne newline (\n).
sorontar
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.