Por que o separador de unidades (ASCII 31) é invisível na saída do terminal?

17

O caractere ASCII do separador de unidades (ASCII 31, octal 37) é visível no Vim como a ^_. Mas se eu imprimir o mesmo arquivo no terminal, o caractere será invisível. Isso faz com que os campos em uma linha fiquem presos juntos:

# 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

Suponho que posso tornar o separador de unidades visível com cat -v:

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

Mas isso é bastante complicado. Por que o separador de unidades não tem uma representação visível quando impresso em stdout no shell Bash? Não consigo nem copiar e colar a saída do shell corretamente; o separador de unidades se perde no processo.

dan
fonte
Nem todos os caracteres são imprimíveis, o separador de unidades é um deles. Alguns editores o exibirão de alguma forma para tornar possível a edição. Você precisa convertê-lo em uma sequência de caracteres imprimíveis, e talvez em uma fonte / cor diferente, para reduzir a ambiguidade.
Ctrl-alt-delor 5/05
3
Os códigos ASCII abaixo de 31 e 127 destinam-se a fazer com que um terminal ou dispositivo faça alguma coisa (por isso, são chamados de códigos de controle) ou representam algo em um protocolo (como EOT ou SOH), em vez de exibir algo. Ele ouve quando os terminais eram do tipo máquinas de escrever e coisas como dizer a um teletipo para retornar o carro eram fisicamente necessárias. Os editores podem optar por renderizá-los usando a notação "^", pois você está editando algo e não deseja que o terminal efetue o que os códigos de controle estão pedindo.
LawrenceC
11
@LawrenceC: O código 127 realmente pretendia fazer com que um terminal não fizesse nada . Se alguém estivesse perfurando uma fita e cometesse um erro, apertaria um botão para fazer o backup da fita em um espaço e pressionaria "esfregar", para perfurar tudo. oito buracos. Quando o leitor encontrava o caractere com todos os furos, ele o enviava pelo fio, mas o destinatário podia simplesmente ignorá-lo.
Supercat

Respostas:

19

O UScaractere separador de unidade ( ), também conhecido como IS1, está na cntrlclasse de caracteres e não está na printclasse de caracteres. É um caractere de controle destinado a organizar o texto em grupos, para programas projetados para usar essas informações . Em geral, os caracteres não imprimíveis provavelmente serão interpretados e renderizados de maneira diferente em diferentes programas ou ambientes.

O motivo para vê-lo representado como ^_no Vim é porque o Vim é um editor interativo. Ele pode renderizar livremente caracteres não imprimíveis como desejar, desde que o caractere binário correto seja gravado no disco.

Você não pode obter o mesmo comportamento no shell porque os programas de shell Unix são escritos para operar e passar texto sem formatação um para o outro. Quando você catcria um arquivo, o texto gravado no terminal deve ser o que realmente está no arquivo.

Isso deixa para o dispositivo terminal interpretar o personagem. E verifica-se que alguns emuladores de terminais fazem tornar o USpersonagem de forma diferente dos outros. No gnome-terminal(ou em qualquer vteterminal baseado em), o caractere será renderizado como uma caixa contendo o código hexadecimal 001F. Em xtermou rxvt, o personagem é realmente invisível.

Mike Miller
fonte
Bem, eu não diria que USé totalmente invisível. Quando insiro esse caractere em um terminal com Ctrl+/(confirmado via <C-v><C-/>), ele exclui uma quantidade imprevisível de texto na linha. Eu não entendo completamente seu comportamento, mas parece ter algum tipo de efeito de "guia inversa", onde, em vez de inserir vários espaços, exclui vários caracteres, mas às vezes insere texto aleatoriamente, por isso é confuso .
Braden Best
10

O separador de unidades está no intervalo ASCII de caracteres de controle e, portanto, não possui (ou não costuma ter) uma representação visual.

O Vim e alguns outros editores os exibem, para que você possa editá-los. Como você notou, também cat -vexibe. A página de manual mostra, que -vé a forma abreviada de --show-nonprinting, que faz com que substitua os caracteres não imprimíveis por uma representação imprimível, que não é o conteúdo original do arquivo e, portanto, pode causar problemas, se a saída for realmente para outro programa .

A representação que você vê já sugere que é um caractere de controle: um caractere anexado com a ^é uma notação comum para Ctrl+ o caractere, que é a combinação de teclas que produz esse caractere em um terminal. Ctrl+ _permitirá inserir o separador de unidades no vim, por exemplo. Mas outro editor ou algum visualizador da GUI pode exibir o código hexadecimal, um espaço reservado ou algo completamente diferente.

Como o seu terminal não imprime os caracteres de controle, ele também não é copiado ao selecionar o texto (os caracteres de espaço em branco como nova linha e guia são uma exceção aqui, que também são caracteres de controle). Outro exemplo de caracteres de controle no terminal que geralmente são ignorados ao copiar são os códigos de cores, que são um ESCcaractere seguido pelo código para colorir o texto.

Portanto, para mostrar os caracteres no seu terminal, não há outra maneira senão usar um programa que substitua o separador da unidade por algum caractere imprimível.

crater2150
fonte
3

Um pouco na margem das outras respostas (muito boas), se você quiser alterar apenas o caractere de controle ^_ao exibir o conteúdo do arquivo, poderá transliterá- lo usando o trutilitário (e um pouco de sintaxe compatível com o bash) :

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

Se você precisar substituir esse caractere de controle por seu formulário "expandido", precisará sed:

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

Observe a sintaxe $'\cX': essa sintaxe informa seu (shell compatível com bash) para substituir o caractere de controle correspondente. Consulte a Wikipedia para obter uma lista de alias de caracteres de controle usando a "notação de sinal de intercalação". Se você não gosta dessa sintaxe, pode preferir usar a notação octal $'\037'ou hexadecimal $'\x1f'.

Sylvain Leroux
fonte