Das TAB
Zeichen ist ein Steuerzeichen, das beim Senden an ein Terminal¹ den Cursor des Terminals zum nächsten Tabulator bewegt. Standardmäßig sind die Tabulatoren in den meisten Terminals 8 Spalten voneinander entfernt, dies ist jedoch konfigurierbar.
Sie können auch in unregelmäßigen Abständen Tabulatoren setzen:
$ tabs 3 9 11; printf '\tx\ty\tz\n'
x y z
Nur das Terminal weiß, wie viele Spalten rechts ein TAB den Cursor bewegt.
Sie können diese Informationen erhalten, indem Sie die Cursorposition vor und nach dem Senden der Registerkarte vom Terminal abfragen.
Wenn Sie diese Berechnung für eine bestimmte Zeile von Hand durchführen möchten und davon ausgehen, dass diese Zeile in der ersten Spalte des Bildschirms gedruckt wird, müssen Sie:
- wissen, wo die Tabulatoren sind²
- kennen die Anzeigebreite jedes Zeichens
- kennen die Breite des Bildschirms
- Entscheiden Sie, ob Sie andere Steuerzeichen wie
\r
(wodurch der Cursor in die erste Spalte \b
bewegt wird ) oder den Cursor zurück bewegen möchten ...).
Dies kann vereinfacht werden, wenn Sie davon ausgehen, dass die Tabulatoren alle 8 Spalten angezeigt werden, die Zeile in den Bildschirm passt und keine anderen Steuerzeichen oder Zeichen (oder Nichtzeichen) vorhanden sind, die Ihr Terminal nicht richtig anzeigen kann.
Mit GNU wc
, wenn die Zeile gespeichert ist in $line
:
width=$(printf %s "$line" | wc -L)
width_without_tabs=$(printf %s "$line" | tr -d '\t' | wc -L)
width_of_tabs=$((width - width_without_tabs))
wc -L
gibt die Breite der breitesten Linie in der Eingabe an. Dazu wird wcwidth(3)
die Breite der Zeichen bestimmt und angenommen, dass die Tabulatoren alle 8 Spalten sind.
Für Nicht-GNU-Systeme und mit denselben Annahmen siehe @ Kusalanandas Ansatz . Es ist sogar noch besser, da Sie damit die Tabulatoren angeben können, aber derzeit leider nicht mit GNU funktionieren expand
(zumindest), wenn die Eingabe Mehrbytezeichen oder Zeichen mit einer Breite von 0 (wie das Kombinieren von Zeichen) oder Zeichen mit doppelter Breite enthält.
¹ Beachten Sie jedoch stty tab3
, dass in diesem Fall die tty-Geräteleitendisziplin die Tabulatorverarbeitung übernimmt (TAB in Leerzeichen konvertieren, basierend auf der eigenen Vorstellung, wo sich der Cursor möglicherweise befindet, bevor er an das Terminal gesendet wird) und Tabulatorstopps alle 8 Spalten implementiert. Beim Testen unter Linux scheint es richtig mit CR-, LF- und BS-Zeichen sowie Multibyte-UTF-8-Zeichen umzugehen (vorausgesetzt, es iutf8
ist auch aktiviert ), aber das war es auch schon. Es wird davon ausgegangen, dass alle anderen Nicht-Steuerzeichen (einschließlich Zeichen mit der Breite Null und der doppelten Breite) eine Breite von 1 haben. Es verarbeitet (offensichtlich) keine Escape-Sequenzen und wird nicht richtig umbrochen. Dies ist wahrscheinlich für Terminals gedacht, die Tab-Verarbeitung kann nicht durchgeführt werden.
In jedem Fall muss die tty-Zeilendisziplin wissen, wo sich der Cursor befindet, und die oben genannten Heuristiken verwenden, da bei Verwendung des icanon
Zeileneditors (z. B. bei der Eingabe von Text für solche Anwendungen cat
kein eigener Zeileneditor implementiert wird) Drücken Sie TabBackspace, die Zeilendisziplin muss wissen, wie viele BS-Zeichen gesendet werden müssen, um das Tabulatorzeichen für die Anzeige zu löschen . Wenn Sie ändern, wo sich die Tabulatoren befinden (wie bei tabs 12
), werden Sie feststellen, dass Tabulatoren nicht richtig gelöscht werden. Gleiches gilt, wenn Sie vor dem Drücken Zeichen mit doppelter Breite eingeben TabBackspace.
² Dazu können Sie Tabulatorzeichen senden und nach jedem die Cursorposition abfragen. Etwas wie:
tabs=$(
saved_settings=$(stty -g)
stty -icanon min 1 time 0 -echo
gawk -vRS=R -F';' -vORS= < /dev/tty '
function out(s) {print s > "/dev/tty"; fflush("/dev/tty")}
BEGIN{out("\r\t\33[6n")}
$NF <= prev {out("\r"); exit}
{print sep ($NF - 1); sep=","; prev = $NF; out("\t\33[6n")}'
stty "$saved_settings"
)
Dann können Sie dies als expand -t "$tabs"
die Lösung von @ Kusalananda verwenden.
x
) ersetzen, bevor Sie es aufrufen.expand
Andernfalls würden Sie auch die Leerzeichen zählen, die ursprünglich in der Eingabe enthalten waren.expand
Es wird auch davon ausgegangen, dass alle 8 Spalten Tabulatoren gesetzt werden (obwohl Sie dies mit Optionen ändern können). Beachten Sie, dass die GNU-Implementierung keine Mehrbyte-Zeichen unterstützt (geschweige denn Zeichen mit 0 oder doppelter Breite). IIRC das FreeBSD ist OK.Mit
perl
:Alternative:
Sie können 8 oben mit einem anderen Wert ändern, wenn TABs eine andere Länge haben sollen.
quelle
Auch mit
expand
, aber mit Bash-Parameter-Manipulation, um die Anzahl der Leerzeichen zu zählen:quelle