Il TAB
personaggio è un carattere di controllo che, quando inviato a un terminale¹, sposta il cursore del terminale al tab-stop successivo. Per impostazione predefinita, nella maggior parte dei terminali, le tabulazioni sono separate da 8 colonne, ma è configurabile.
Puoi anche avere tabulazioni a intervalli irregolari:
$ tabs 3 9 11; printf '\tx\ty\tz\n'
x y z
Solo il terminale sa quante colonne a destra una TAB sposta il cursore.
È possibile ottenere tali informazioni eseguendo una query sulla posizione del cursore dal terminale prima e dopo l'invio della scheda.
Se vuoi fare quel calcolo a mano per una data linea e supponendo che quella linea sia stampata nella prima colonna dello schermo, dovrai:
- sapere dove sono le tabulazioni²
- conoscere la larghezza di visualizzazione di ogni personaggio
- conoscere la larghezza dello schermo
- decidere se si desidera gestire altri caratteri di controllo come
\r
(che sposta il cursore sulla prima colonna) o \b
che sposta il cursore indietro ...)
Può essere semplificato se si presume che le tabulazioni siano ogni 8 colonne, la linea si adatti allo schermo e non vi siano altri caratteri di controllo o caratteri (o non caratteri) che il terminale non può visualizzare correttamente.
Con GNU wc
, se la linea è memorizzata 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
fornisce la larghezza della linea più larga nel suo input. Lo fa usando wcwidth(3)
per determinare la larghezza dei caratteri e supponendo che le tabulazioni siano ogni 8 colonne.
Per i sistemi non GNU, e con le stesse ipotesi, vedi l'approccio di @ Kusalananda . È ancora meglio in quanto consente di specificare i punti di tabulazione ma purtroppo attualmente non funziona con GNU expand
(almeno) quando l'input contiene caratteri multi-byte o 0-larghezza (come la combinazione di caratteri) o caratteri a doppia larghezza.
¹ notare che, in tal caso stty tab3
, la disciplina della linea del dispositivo tty assumerà il controllo dell'elaborazione della scheda (converte TAB in spazi in base alla propria idea di dove potrebbe essere il cursore prima di inviarlo al terminale) e implementa le tabulazioni ogni 8 colonne. Test su Linux, sembra gestire correttamente i caratteri CR, LF e BS, nonché quelli UTB-8 multibyte (a condizione che iutf8
sia attivo), ma questo è tutto. Presuppone che tutti gli altri caratteri non di controllo (inclusi i caratteri a larghezza zero, a doppia larghezza) abbiano una larghezza di 1, (ovviamente) non gestisce le sequenze di escape, non si avvolge correttamente ... Probabilmente è destinato a terminali che impossibile eseguire l'elaborazione delle schede.
In ogni caso, la disciplina della linea tty ha bisogno di sapere dove si trova il cursore e usa quelle euristiche sopra, perché quando si utilizza l' icanon
editor di linee (come quando si immette il testo per applicazioni come cat
quelle non implementano il proprio editor di linee), quando si premere TabBackspace, la disciplina di linea deve sapere quanti caratteri BS inviare per cancellare quel carattere Tab per la visualizzazione. Se cambi dove si trovano le tabulazioni (come con tabs 12
), noterai che le schede non vengono cancellate correttamente. Lo stesso se si immettono caratteri a doppia larghezza prima di premere TabBackspace.
² Per questo, è possibile inviare caratteri di tabulazione e interrogare la posizione del cursore dopo ognuno. Qualcosa di simile a:
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"
)
Quindi, puoi usarlo come expand -t "$tabs"
usando la soluzione di @ Kusalananda.
x
) prima di chiamareexpand
altrimenti, conteresti anche gli spazi che erano inizialmente nell'input.