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

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

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

# 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 da unidade se perde no processo.

Responder1

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

A razão pela qual você o vê representado como ^_no Vim é porque o Vim é um editor interativo. Ele pode renderizar livremente caracteres não imprimíveis da maneira que 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 shell do Unix são escritos para operar e passar texto simples entre si. Quando você catcria um arquivo, o texto gravado no terminal deve ser o que realmente está no arquivo.

Então isso deixa para o dispositivo terminal interpretar o personagem. E acontece que alguns emuladores de terminalfazertornar o USpersonagem diferente dos outros. Em 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 é de fato invisível.

Responder2

O separador de unidades está na faixa ASCII dePersonagens de controlee, portanto, não tem (ou normalmente não deveria) ter uma representação visual.

O Vim e alguns outros editores os exibem, para que você possa editá-los. Como você notou, cat -vtambém exibe. A página de manual mostra que essa -vé a forma abreviada de --show-nonprinting, o que faz com que ele substitua os caracteres não imprimíveis por uma representação imprimível, que não é o conteúdo original do arquivo e pode, portanto, 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 prefixado 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á que você insira o separador de unidades no vim, por exemplo. Mas outro editor ou algum visualizador de 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 tabulação 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 na cópia são os códigos de cores, que são um ESCcaractere seguido do 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 de unidades por algum caractere imprimível.

Responder3

Um pouco à margem das outras respostas (muito boas), se quiser alterarapenaso caractere de controle ^_ao exibir o conteúdo do arquivo, você pode querertransliterarusando o trutilitário (e um pouco de sintaxe compatível com bash):

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

Se precisar substituir esse caractere de controle pela sua forma "expandida", você precisará sed:

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

Observe a sintaxe $'\cX': esta sintaxe informa ao seu (shell compatível com bash) para substituir o caractere de controle correspondente. Verwikipedia para obter uma lista de alias de personagens de controleusando a "notação circunflexa". Se você não gosta dessa sintaxe, talvez prefira usar a notação octal $'\037'ou hexadecimal .$'\x1f'

informação relacionada