Pourquoi le séparateur d'unités (ASCII 31) est-il invisible dans la sortie du terminal?

17

Le caractère ASCII du séparateur d'unités (ASCII 31, octal 37) est visible dans Vim sous la forme d'un ^_. Mais si j'imprime le même fichier sur le terminal, le caractère est invisible. Cela provoque le blocage des champs d'une ligne:

# In Vim and less:

first field^_second field^_last field

# cat the same file to terminal:
cat delim.txt
first fieldsecond fieldlast field

# print 2nd field with awk 
cat delim.txt | awk 'BEGIN {FS = "\037"} {print $2}'
second field

Je suppose que je peux rendre le séparateur d'unités visible avec cat -v:

cat -v delim.txt
first field^_second field^_last field

Mais c'est assez lourd. Pourquoi le séparateur d'unités n'a-t-il pas une représentation visible lorsqu'il est imprimé sur stdout dans le shell Bash? Je ne peux même pas copier et coller correctement la sortie du shell; le séparateur d'unités se perd dans le processus.

dan
la source
Tous les caractères ne sont pas imprimables, le séparateur d'unités en fait partie. Certains éditeurs l'afficheront d'une manière ou d'une autre pour rendre l'édition possible. Vous devez le traduire en une séquence de caractères imprimables, et peut-être une police / couleur différente, pour réduire l'ambiguïté.
ctrl-alt-delor
3
Les codes ASCII inférieurs à 31 et 127 sont destinés à amener un terminal ou un périphérique à faire quelque chose (d'où la raison pour laquelle ils sont appelés codes de contrôle), ou à représenter quelque chose dans un protocole (comme EOT ou SOH), par opposition à afficher quelque chose. Il nous rappelle quand les terminaux étaient des appareils de type machine à écrire et que des choses comme dire à un téléscripteur de retourner en chariot étaient physiquement nécessaires. Les éditeurs peuvent choisir de les rendre en utilisant la notation «^» puisque vous modifiez quelque chose et ne voulez pas que le terminal fasse réellement ce que les codes de contrôle demandent.
LawrenceC
1
@LawrenceC: Code 127 en fait destiné à empêcher un terminal de faire quoi que ce soit , si quelqu'un poinçonnait une bande et faisait une erreur, on tapait sur un bouton pour sauvegarder la bande d'un espace et frappait "rub-out", pour tout poinçonner huit trous. Lorsque le lecteur rencontrait le caractère perforé, il l'envoyait sur le fil mais le destinataire pouvait simplement l'ignorer.
supercat

Réponses:

19

Le caractère séparateur d'unité ( US), également appelé IS1, se trouve dans la cntrlclasse de caractères et n'est pas dans la printclasse de caractères. Il s'agit d'un caractère de contrôle destiné à organiser le texte en groupes, pour les programmes conçus pour utiliser ces informations . En général, les caractères non imprimables vont probablement être interprétés et rendus différemment dans différents programmes ou environnements.

La raison pour laquelle vous le voyez représenté comme ^_dans Vim est que Vim est un éditeur interactif. Il peut restituer librement les caractères non imprimables comme il le souhaite, tant que le caractère binaire correct est écrit sur le disque.

Vous ne pouvez pas obtenir le même comportement dans le shell car les programmes shell Unix sont écrits pour fonctionner et se transmettre du texte brut. Lorsque vous catun fichier, le texte qui est écrit sur le terminal doit être ce qui est réellement dans le fichier.

Cela laisse donc au terminal le soin d'interpréter le personnage. Et il se trouve que certains émulateurs font rendre le UScaractère différemment des autres. Dans gnome-terminal(ou tout vteterminal basé sur), le caractère sera rendu sous la forme d'une boîte contenant le code hexadécimal 001F. Dans xtermou rxvt, le personnage est en effet invisible.

Mike Miller
la source
Eh bien, je ne dirais pas que USc'est totalement invisible. Lorsque j'insère ce caractère dans un terminal avec Ctrl+/(confirmé via <C-v><C-/>), il supprime une quantité imprévisible de texte sur la ligne. Je ne comprends pas bien son comportement, mais il semble avoir principalement une sorte d'effet "onglet inversé" où au lieu d'insérer un certain nombre d'espaces, il supprime un certain nombre de caractères, mais parfois il insère au hasard du texte, donc c'est déroutant .
Braden Best
10

Le séparateur d'unités est dans la plage ASCII des caractères de contrôle et n'a donc pas (ou ne devrait généralement pas) de représentation visuelle.

Vim et certains autres éditeurs les affichent, vous pouvez donc les modifier. Comme vous l'avez remarqué, l' cat -vaffiche également. La page de manuel montre, c'est-à- -vdire la forme abrégée de --show-nonprinting, ce qui oblige à remplacer les caractères non imprimables par une représentation imprimable, qui n'est pas le contenu original du fichier et pourrait donc causer des problèmes, si la sortie est en fait vers un autre programme .

La représentation que vous voyez indique déjà qu'il s'agit d'un caractère de contrôle: un caractère précédé d'un ^est une notation courante pour Ctrl+ le caractère, qui est la combinaison de touches qui produit ce caractère dans un terminal. Ctrl+ _vous permettra par exemple de saisir le séparateur d'unités dans vim. Mais un autre éditeur ou un visualiseur GUI peut afficher le code hexadécimal, un espace réservé ou quelque chose de complètement différent.

Comme votre terminal n'imprime pas les caractères de contrôle, il n'est pas non plus copié lors de la sélection du texte (les caractères blancs comme la nouvelle ligne et tabulation sont une exception ici, qui sont aussi des caractères de contrôle). Un autre exemple de caractères de contrôle dans le terminal qui sont généralement ignorés lors de la copie sont les codes de couleur, qui sont un ESCcaractère suivi du code de coloration du texte.

Donc, pour afficher les caractères sur votre terminal, il n'y a pas d'autre moyen que d'utiliser un programme qui remplace le séparateur d'unités par un caractère imprimable.

cratère2150
la source
3

Un peu en marge des autres (très bonnes) réponses, si vous souhaitez modifier uniquement le caractère de contrôle ^_lors de l'affichage du contenu du fichier, vous pouvez le translitérer à l'aide de l' trutilitaire (et un peu de syntaxe compatible bash) :

# Replace the control character US (^_) by *one* other character
$ cat my.file | tr $'\c_' ':'

Si vous devez remplacer ce caractère de contrôle par sa forme "étendue", vous aurez besoin à la sedplace:

# Replace the control character US (^_) by any string
cat /tmp/f | sed s/$'\c_'/^_/g

Veuillez noter la syntaxe $'\cX': cette syntaxe informe votre (shell compatible bash) de remplacer le caractère de contrôle correspondant. Voir wikipedia pour une liste d'alias de caractères de contrôle utilisant la "notation caret". Si vous n'aimez pas cette syntaxe, vous préférerez peut-être utiliser la notation octale $'\037'ou hexadécimale à la $'\x1f'place.

Sylvain Leroux
la source