Pourquoi clang génère-t-il du texte inintelligible lorsqu'il est redirigé?

20

J'essaie d'enregistrer la sortie d'une commande dans un fichier. La commande est:

clang -Xclang -ast-dump -fsyntax-only main.cpp > output.txt

Cependant le fichier output.txt résultant lorsqu'il est ouvert (par gedit et jedit sur ubuntu) me donne ceci:

[0;1;32mTranslationUnitDecl[0m[0;33m 0x4192020[0m <[0;33m<invalid sloc>[0m> [0;33m<invalid sloc>[0m
[0;34m|-[0m[0;1;32mTypedefDecl[0m[0;33m 0x4192558[0m <[0;33m<invalid sloc>[0m> [0;33m<invalid sloc>[0m implicit[0;1;36m __int128_t[0m [0;32m'__int128'[0m
[0;34m| `-[0m[0;32mBuiltinType[0m[0;33m 0x4192270[0m [0;32m'__int128'[0m
[0;34m|-[0m[0;1;32mTypedefDecl[0m[0;33m 0x41925b8[0m <[0;33m<invalid sloc>[0m> [0;33m<invalid sloc>[0m implicit[0;1;36m __uint128_t[0m [0;32m'unsigned __int128'[0m
[0;34m| `-[0m[0;32mBuiltinType[0m[0;33m 0x4192290[0m [0;32m'unsigned __int128'[0m
...

Quand ça devrait vraiment ressembler à ça:

TranslationUnitDecl 0x4e46020 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x4e46558 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x4e46270 '__int128'
|-TypedefDecl 0x4e465b8 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x4e46290 'unsigned __int128'
...

J'ai pensé que cela pourrait être un problème d'encodage, j'ai vérifié l'encodage du fichier, file -bi output.txtqui sort text/plain; charset=us-ascii.

Je pensais que si je modifiais l'encodage en utf-8, le problème serait résolu, j'ai donc essayé ceci:

clang -Xclang -ast-dump -fsyntax-only main.cpp | iconv -f us-ascii -t UTF-8 > output.txt

mais cela n'a pas fait de différence.

Que puis-je faire pour résoudre ce problème?

Le problème n'est pas que j'essaie d'afficher la version surlignée en syntaxe (je n'ai pas eu de problème pour la visualiser en premier lieu). Je dois enregistrer l'AST généré par clang dans un fichier, puis l'analyser, ce qui serait difficile avec les informations de couleur restantes.

maou
la source
4
Il est à noter que >cela ne génère pas de sortie, il désigne simplement au shell que vous souhaitez placer la sortie de votre clangcommande dans le fichier donné, plutôt que dans le terminal. Après cela, vous le visualisez d'une manière qui n'autorise pas les codes de couleur de la même manière. Si vous étiez dans catle fichier, cela fonctionnerait comme le terminal prendrait le relais, et vous pouvez faire de lessmême avec l' -Rindicateur.
Sammitch
@Scott - Je n'essaie pas de visualiser la sortie, j'essaie de l'enregistrer dans un fichier sans laisser les informations de couleur, ce qui rendrait l'analyse du fichier inutilement compliquée.
maou

Réponses:

54

Cela n'a rien à voir avec les pages de codes / l'encodage. Votre sortie n'est pas du texte brut. Il contient les séquences comme [0;1;32m. Ces chaînes (il y a un caractère [d'échappement] non illustré avant chacune d'elles) sont des instructions au terminal pour afficher le texte en gras, en italique, en différentes couleurs, etc. le soutient.

Il devrait y avoir une option pour dire à clang de ne pas essayer d'embellir la sortie, mais d'utiliser du texte brut à la place. Consultez le manuel. (Je n'en ai pas à portée de main, donc je ne peux pas vous dire quelle serait la commande appropriée.)

Tonny
la source
15
Merci, c'était la cause. J'ai essayé clang -Xclang -ast-dump -fsyntax-only -fno-color-diagnostics main.cpp > output.txtce qui m'a donné la sortie correcte.
maou
9
Un autre correctif, si Clang se comporte raisonnablement bien (ce qui n'est évidemment pas le cas, s'il envoie des codes de terminal sans vérification isatty(stdout)) est de le définir TERM(par exemple) dumb.
Toby Speight
4
Re "Il en résulte une sortie plus facile à lire, si votre terminal le prend en charge.", C'est, bien sûr, une opinion. Ne fonctionne pas toujours de cette façon, comme par exemple lorsque l'application de colorisation affiche du texte bleu foncé sur votre fond noir :-(
jamesqf
4
Tout logiciel raisonnable doit détecter que sa sortie est redirigée vers le fichier et désactiver la colorisation dans ce cas.
n0rd
1
@ n0rd Idéalement oui, mais j'ai vu suffisamment de situations où isattty () n'a pas reçu la valeur false sur la sortie redirigée. Et dans certains cas, un utilisateur peut souhaiter que les codes d'échappement soient redirigés (par exemple, pour afficher plus tard ou pour diriger vers netcat pour afficher sur un autre système, juste pour donner 2 cas d'utilisation). Essayez donc de deviner, mais permettez également à l'utilisateur de l'activer / désactiver en remplaçant la supposition en cas d'erreur. Ce serait la meilleure solution.
Tonny
12

Alternativement, au lieu de supprimer les couleurs de la sortie, vous pouvez afficher la sortie colorée dans votre terminal en utilisant l'option brute de less

less -r output.txt
987poiuytrewq
la source
2

Ces caractères, tels que [0;33mressemblent à moi au contrôle de sortie du terminal. Ils font partie d'un ensemble de séquences d'échappement fréquemment utilisées pour appliquer des couleurs au texte dans le terminal. Dans son état brut comme celui-ci, il est également souvent utilisé pour appliquer la couleur à l'invite bash elle-même - voici ce que j'utilise depuis .bashrcdes années sur toutes mes machines:

export PS1='\[\033[1;33m\]\u\[\033[1;35m\]@\[\033[1;32m\]\h\[\033[0;36m\]\w\[\033[1;37m\]\$ \[\033[0;37m\]'

(La plupart pensent que c'est moche, mais j'aime ça).

Voyez si vous pouvez trouver un commutateur pour supprimer tout codage couleur ou similaire de la sortie de vos commandes et voir si cela aide.

Jarmund
la source
13
[...] "ressemble au contrôle de sortie de bash pour moi" Ils n'ont rien à voir avec bash. C'est le terminal à quoi ils servent.
glglgl
1
Comme l'a dit @glglgl, ils ne sont pas spécifiques à Bash, ils sont xtermliés à quelque chose. Voir cette excellente réponse du développeur principal de xterm.
chat
@glglgl Très bien, la réponse a été modifiée en conséquence. Je l'ai vu pour la première fois lors de la migration de fBSD vers linux il y a quelques années, ce qui était aussi lorsque j'ai commencé à utiliser bash, donc je pensais que c'était un produit de ce dernier.
Jarmund