El TAB
carácter es un carácter de control que cuando se envía a un terminal¹ hace que el cursor del terminal se mueva a la siguiente tabulación. Por defecto, en la mayoría de las terminales, las tabulaciones están separadas por 8 columnas, pero eso es configurable.
También puede tener tabulaciones a intervalos irregulares:
$ tabs 3 9 11; printf '\tx\ty\tz\n'
x y z
Solo el terminal sabe cuántas columnas a la derecha moverá el cursor una TAB.
Puede obtener esa información consultando la posición del cursor desde el terminal antes y después de que se haya enviado la pestaña.
Si desea hacer ese cálculo a mano para una línea determinada y suponiendo que esa línea se imprime en la primera columna de la pantalla, deberá:
- saber dónde están las tabulaciones²
- saber el ancho de visualización de cada personaje
- saber el ancho de la pantalla
- decida si desea manejar otros caracteres de control como
\r
(que mueve el cursor a la primera columna) o \b
que mueve el cursor hacia atrás ...)
Se puede simplificar si supone que las tabulaciones son cada 8 columnas, la línea cabe en la pantalla y no hay otros caracteres de control o caracteres (o no caracteres) que su terminal no pueda mostrar correctamente.
Con GNU wc
, si la línea se almacena en $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
da el ancho de la línea más ancha en su entrada. Lo hace usando wcwidth(3)
para determinar el ancho de los caracteres y suponiendo que las tabulaciones son cada 8 columnas.
Para los sistemas que no son GNU, y con los mismos supuestos, ver el enfoque de @ Kusalananda . Es incluso mejor, ya que le permite especificar las tabulaciones, pero desafortunadamente actualmente no funciona con GNU expand
(al menos) cuando la entrada contiene caracteres de varios bytes o ancho 0 (como combinar caracteres) o caracteres de doble ancho.
Sin embargo, tenga en cuenta que si lo hace stty tab3
, la disciplina de línea del dispositivo tty se hará cargo del procesamiento de la pestaña (convierta TAB en espacios basados en su propia idea de dónde podría estar el cursor antes de enviarlo al terminal) y la pestaña de implementación se detiene cada 8 columnas. Al probar en Linux, parece manejar correctamente los caracteres CR, LF y BS, así como los multibyte UTF-8 (siempre iutf8
que también esté activado), pero eso es todo. Asume que todos los demás caracteres que no son de control (incluidos los caracteres de ancho cero y doble ancho) tienen un ancho de 1, (obviamente) no maneja secuencias de escape, no se ajusta correctamente ... Eso probablemente esté destinado a terminales que No se puede hacer el procesamiento de pestañas.
En cualquier caso, la disciplina de línea tty necesita saber dónde está el cursor y usa las heurísticas anteriores, porque cuando usa el icanon
editor de línea (como cuando ingresa texto para aplicaciones como cat
esa, no implementa su propio editor de línea), cuando presione TabBackspace, la disciplina de línea necesita saber cuántos caracteres BS enviar para borrar ese carácter Tab para mostrar. Si cambia dónde están las tabulaciones (como con tabs 12
), notará que las pestañas no se borran correctamente. Lo mismo si ingresa caracteres de doble ancho antes de presionar TabBackspace.
² Para eso, puede enviar caracteres de tabulación y consultar la posición del cursor después de cada uno. Algo como:
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"
)
Entonces, puedes usar eso como expand -t "$tabs"
la solución de @ Kusalananda.
x
) antes de llamar de loexpand
contrario, también estaría contando los espacios que inicialmente estaban en la entrada también.