Warum ist das Einheitentrennzeichen (ASCII 31) in der Terminalausgabe nicht sichtbar?

17

Das Einheitentrennzeichen ASCII (ASCII 31, Oktal 37) ist in Vim als sichtbar ^_. Wenn ich aber dieselbe Datei auf das Terminal drucke, ist das Zeichen unsichtbar. Dies führt dazu, dass die Felder in einer Zeile zusammenkleben:

# 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

Ich nehme an, ich kann das Einheitentrennzeichen mit cat -v sichtbar machen:

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

Das ist aber ziemlich umständlich. Warum hat das Einheitentrennzeichen keine sichtbare Darstellung, wenn es in der Bash-Shell auf stdout gedruckt wird? Ich kann die Shell-Ausgabe nicht einmal richtig kopieren und einfügen. Der Einheitentrenner geht dabei verloren.

Dan
quelle
Es können nicht alle Zeichen gedruckt werden, das Trennzeichen ist eines davon. Einige Editoren zeigen es auf irgendeine Weise an, um die Bearbeitung zu ermöglichen. Sie müssen es in eine Folge druckbarer Zeichen und möglicherweise in eine andere Schriftart / Farbe übersetzen, um Mehrdeutigkeiten zu vermeiden.
ctrl-alt-delor
3
ASCII-Codes unter 31 und 127 sollen ein Terminal oder Gerät dazu veranlassen, etwas zu tun (daher werden sie als Steuercodes bezeichnet) oder für etwas in einem Protokoll (wie EOT oder SOH) zu stehen, anstatt etwas anzuzeigen. Es hört sich an, als Terminals schreibmaschinenähnliche Geräte waren, und Dinge wie das Senden eines Teletyps zum Rücktransport waren physisch erforderlich. Redakteure können sie mit der "^" - Notation rendern, da Sie gerade etwas bearbeiten und nicht möchten, dass das Terminal tatsächlich tut, was die Steuercodes verlangen.
LawrenceC
1
@LawrenceC: Code 127 sollte eigentlich bewirken, dass ein Terminal nichts unternimmt. Wenn man ein Band locht und einen Fehler macht, drückt man eine Taste, um das Band um ein Leerzeichen zu sichern , und drückt auf "Abwischen", um alle zu lochen acht Löcher. Wenn der Leser auf das durchgestanzte Zeichen stieß, wurde es über den Draht gesendet, aber der Empfänger konnte es einfach ignorieren.
Supercat

Antworten:

19

Das USZeichen unit separator ( ), auch bekannt als IS1, gehört zur cntrlZeichenklasse und nicht zur printZeichenklasse. Es ist ein Steuerzeichen, das zum Organisieren von Text in Gruppen für Programme vorgesehen ist, die diese Informationen verwenden sollen . Im Allgemeinen werden nicht druckbare Zeichen wahrscheinlich in verschiedenen Programmen oder Umgebungen unterschiedlich interpretiert und gerendert.

Der Grund für die Darstellung ^_in Vim ist, dass Vim ein interaktiver Editor ist. Es kann nicht druckbare Zeichen beliebig rendern, solange das richtige Binärzeichen auf die Festplatte geschrieben wird.

Sie können nicht dasselbe Verhalten in der Shell erzielen, da Unix-Shell-Programme so geschrieben sind, dass sie miteinander arbeiten und einfachen Text weitergeben. Wenn Sie cateine Datei erstellen, muss der Text, der in das Terminal geschrieben wird, dem entsprechen, der sich tatsächlich in der Datei befindet.

Damit bleibt es dem Endgerät überlassen, den Charakter zu interpretieren. Und es stellt sich heraus , dass einige Terminal - Emulatoren tun machen den USCharakter anders als andere. In gnome-terminal(oder einem beliebigen vteTerminal) wird das Zeichen als Feld mit dem Hex-Code gerendert 001F. In xtermoder rxvtist der Charakter tatsächlich unsichtbar.

Mike Miller
quelle
Nun, ich würde nicht sagen, dass USes völlig unsichtbar ist. Wenn ich dieses Zeichen in ein Terminal mit Ctrl+/(bestätigt durch <C-v><C-/>) einfüge, wird eine unvorhersehbare Textmenge in der Zeile gelöscht. Ich verstehe sein Verhalten nicht ganz, aber es scheint hauptsächlich eine Art "Reverse Tab" -Effekt zu haben, bei dem anstatt einer Anzahl von Leerzeichen eine Anzahl von Zeichen gelöscht wird, aber manchmal zufällig Text eingefügt wird, was verwirrend ist .
Braden Best
10

Das Einheitentrennzeichen befindet sich im ASCII-Bereich der Steuerzeichen und verfügt daher nicht über eine visuelle Darstellung (oder sollte dies normalerweise nicht tun).

Vim und einige andere Editoren zeigen sie an, sodass Sie sie bearbeiten können. Wie Sie bemerkt haben, cat -vwird es auch angezeigt. Die Manpage zeigt, dass dies -vdie Kurzform von ist --show-nonprinting, wodurch die nicht druckbaren Zeichen durch eine druckbare Darstellung ersetzt werden. Dies ist nicht der ursprüngliche Inhalt der Datei und kann daher zu Problemen führen, wenn die Ausgabe tatsächlich in einem anderen Programm erfolgt .

Die angezeigte Darstellung weist bereits darauf hin, dass es sich um ein Steuerzeichen handelt: Ein mit einem vorangestelltes Zeichen ^ist eine gebräuchliche Notation für Ctrl+ das Zeichen, die Tastenkombination, die dieses Zeichen in einem Terminal erzeugt. CtrlMit + _können Sie beispielsweise das Einheitentrennzeichen in vim eingeben. Ein anderer Editor oder ein anderer GUI-Viewer zeigt möglicherweise den Hex-Code, einen Platzhalter oder etwas völlig anderes an.

Da Ihr Terminal die Steuerzeichen nicht druckt, wird sie auch bei der Auswahl des Texts nicht kopiert (Ausnahme hiervon sind die Leerzeichen wie Zeilenvorschub und Tabulator, bei denen es sich auch um Steuerzeichen handelt). Ein weiteres Beispiel für Steuerzeichen im Terminal, die beim Kopieren normalerweise ignoriert werden, sind Farbcodes. Hierbei handelt es sich um ein ESCZeichen, auf das der Code zum Färben des Texts folgt.

Um die Zeichen auf Ihrem Terminal anzuzeigen, gibt es keine andere Möglichkeit, als ein Programm zu verwenden, das das Einheitentrennzeichen durch ein druckbares Zeichen ersetzt.

crater2150
quelle
3

Ein bisschen am Rande der anderen (sehr guten) Antworten. Wenn Sie beim Anzeigen des Dateiinhalts nur das Steuerzeichen ändern möchten, möchten ^_Sie es möglicherweise mit dem Dienstprogramm (und ein bisschen bash-kompatibler Syntax) transliterieren.tr :

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

Wenn Sie dieses Steuerzeichen durch seine "erweiterte" Form ersetzen müssen, benötigen Sie sedstattdessen:

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

Bitte beachten Sie die Syntax $'\cX': Diese Syntax weist Ihre (bash-kompatible Shell) an, das entsprechende Steuerzeichen zu ersetzen. In Wikipedia finden Sie eine Liste der Steuerzeichen-Aliasnamen unter Verwendung der "Caret-Notation". Wenn Ihnen diese Syntax nicht gefällt, bevorzugen Sie möglicherweise stattdessen die oktale $'\037'oder hexadezimale $'\x1f'Schreibweise.

Sylvain Leroux
quelle