O TAB
caractere é um caractere de controle que, quando enviado para um terminal¹, faz com que o cursor do terminal se mova para a próxima tabulação. Por padrão, na maioria dos terminais, as paradas de tabulação têm 8 colunas de distância, mas isso é configurável.
Você também pode ter tabulações em intervalos irregulares:
$ tabs 3 9 11; printf '\tx\ty\tz\n'
x y z
Somente o terminal sabe quantas colunas à direita um TAB moverá o cursor.
Você pode obter essas informações consultando a posição do cursor no terminal antes e depois do envio da guia.
Se você deseja fazer esse cálculo manualmente para uma determinada linha e assumindo que a linha seja impressa na primeira coluna da tela, será necessário:
- saber onde estão as paradas de tabulação²
- conhecer a largura de exibição de cada caractere
- conhecer a largura da tela
- decida se deseja manipular outros caracteres de controle como
\r
(que move o cursor para a primeira coluna) ou \b
que move o cursor para trás ...)
Isso pode ser simplificado se você assumir que as paradas de tabulação são a cada 8 colunas, a linha se encaixa na tela e não há outros caracteres de controle ou caracteres (ou não caracteres) que o seu terminal não pode exibir corretamente.
Com o GNU wc
, se a linha estiver armazenada em $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
fornece a largura da linha mais larga em sua entrada. Ele faz isso usando wcwidth(3)
para determinar a largura dos caracteres e assumindo que as paradas de tabulação estejam a cada 8 colunas.
Para sistemas não-GNU e com as mesmas suposições, consulte a abordagem de @ Kusalananda . É ainda melhor, pois permite especificar as paradas da guia, mas infelizmente atualmente não funciona com o GNU expand
(pelo menos) quando a entrada contém caracteres de vários bytes ou largura 0 (como combinar caracteres) ou caracteres de largura dupla.
Though observe que, se o fizer stty tab3
, a disciplina da linha do dispositivo tty assumirá o processamento da guia (converter TAB em espaços com base em sua própria idéia de onde o cursor pode estar antes de enviar para o terminal) e a guia implementar implementará a cada 8 colunas. Testando no Linux, parece lidar adequadamente com caracteres CR, LF e BS, bem como caracteres UTF-8 de vários bytes ( iutf8
também fornecido ), mas é isso. Ele assume que todos os outros caracteres que não são de controle (incluindo caracteres de largura zero e largura dupla) têm uma largura de 1, (obviamente) não lida com seqüências de escape, não é encapsulado adequadamente ... Isso provavelmente é destinado a terminais que não pode processar a guia.
De qualquer forma, a disciplina tty line precisa saber onde está o cursor e usa as heurísticas acima, porque ao usar o icanon
editor de linhas (como quando você digita texto para aplicativos como cat
esse não implementa seu próprio editor de linhas), quando você pressione TabBackspace, a disciplina de linha precisa saber quantos caracteres BS enviar para apagar esse caractere de tabulação para exibição. Se você alterar onde as paradas de tabulação estão (como em tabs 12
), notará que as guias não são apagadas corretamente. O mesmo se você digitar caracteres de largura dupla antes de pressionar TabBackspace.
² Para isso, você pode enviar caracteres de tabulação e consultar a posição do cursor após cada um. 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"
)
Em seguida, você pode usar isso como expand -t "$tabs"
usando a solução do @ Kusalananda.
x
) antes de chamar oexpand
contrário, também contaria os espaços que estavam inicialmente na entrada.