¿Por qué el separador de unidad (ASCII 31) es invisible en la salida del terminal?

17

El carácter ASCII del separador de unidad (ASCII 31, octal 37), es visible en Vim como a ^_. Pero si imprimo el mismo archivo en la terminal, el personaje es invisible. Esto hace que los campos de una línea se atasquen:

# 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

Supongo que puedo hacer que el separador de unidades sea visible con cat -v:

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

Pero esto es bastante engorroso. ¿Por qué el separador de unidades no tiene una representación visible cuando se imprime en stdout en el shell Bash? Ni siquiera puedo copiar y pegar la salida del shell correctamente; el separador de unidad se pierde en el proceso.

dan
fuente
No todos los caracteres son imprimibles, el separador de unidades es uno de estos. Algunos editores lo mostrarán de alguna manera para hacer posible la edición. Necesita traducirlo en una secuencia de caracteres imprimibles, y tal vez una fuente / color diferente, para reducir la ambigüedad.
ctrl-alt-delor 05 de
3
Los códigos ASCII menores de 31 y 127 están destinados a hacer que un terminal o dispositivo haga algo (de ahí que se los llame códigos de control), o represente algo en un protocolo (como EOT o SOH), en lugar de mostrar algo. Se escucha cuando los terminales eran dispositivos tipo máquina de escribir y se necesitaban cosas como decirle un teletipo al retorno de carro. Los editores pueden optar por renderizarlos usando la notación "^", ya que está editando algo y no desea que el terminal realmente haga lo que le piden los códigos de control.
LawrenceC
1
@LawrenceC: el Código 127 en realidad tenía la intención de hacer que un terminal no hiciera nada , si uno estaba perforando una cinta y cometió un error, presionaría un botón para hacer una copia de seguridad de la cinta un espacio y presionar "frotar", para perforar todo Ocho hoyos. Cuando el lector se encuentra con el personaje perforado, lo envía por el cable, pero el destinatario puede ignorarlo.
supercat

Respuestas:

19

El carácter separador de unidades ( US), también conocido como IS1, está en la cntrlclase de caracteres y no está en la printclase de caracteres. Es un carácter de control destinado a organizar el texto en grupos, para programas diseñados para hacer uso de esa información . En general, los caracteres no imprimibles probablemente serán interpretados y representados de manera diferente en diferentes programas o entornos.

La razón por la que lo ves representado como ^_en Vim es porque Vim es un editor interactivo. Puede representar libremente caracteres no imprimibles como quiera, siempre y cuando el carácter binario correcto esté escrito en el disco.

No puede obtener el mismo comportamiento en el shell porque los programas de shell de Unix están escritos para operar y pasar texto sin formato entre sí. Cuando crea catun archivo, el texto que se escribe en el terminal debe ser lo que realmente está en el archivo.

Entonces eso deja al dispositivo terminal interpretar el personaje. Y resulta que algunos emuladores de terminal hacen que el USpersonaje sea diferente de los demás. En gnome-terminal(o cualquier vteterminal basado en), el personaje se representará como un cuadro que contiene el código hexadecimal 001F. En xtermo rxvt, el personaje es realmente invisible.

Mike Miller
fuente
Bueno, yo no diría que USes totalmente invisible. Cuando inserto ese carácter en un terminal con Ctrl+/(confirmado mediante <C-v><C-/>), elimina una cantidad impredecible de texto en la línea. No entiendo completamente su comportamiento, pero parece tener principalmente algún tipo de efecto de "pestaña inversa" donde, en lugar de insertar una cantidad de espacios, elimina una cantidad de caracteres, pero a veces inserta texto al azar, por lo que es confuso .
Braden Best
10

El separador de unidades está en el rango ASCII de caracteres de control y, por lo tanto, no tiene (o no debería tener) una representación visual.

Vim y algunos otros editores los muestran, para que pueda editarlos. Como te diste cuentacat -v también lo muestra. La página de manual muestra, esa -ves la forma abreviada de --show-nonprinting, lo que hace que reemplace los caracteres que no se imprimen con una representación imprimible, que no es el contenido original del archivo y, por lo tanto, podría causar problemas, si la salida es realmente a otro programa .

La representación que ve ya insinúa que es un carácter de control: un carácter antepuesto con a ^es una notación común para Ctrl+ el carácter, que es la combinación de teclas que produce este carácter en un terminal. Ctrl+ _le permitirá ingresar el separador de unidades en vim, por ejemplo. Pero otro editor o algún visor de GUI podría mostrar el código hexadecimal, un marcador de posición o algo completamente diferente.

Como su terminal no imprime los caracteres de control, tampoco se copia al seleccionar el texto (los caracteres de espacio en blanco como nueva línea y tabulación son una excepción aquí, que también son caracteres de control). Otro ejemplo de caracteres de control en el terminal que generalmente se ignoran al copiar son los códigos de color, que son un ESCcarácter seguido del código para colorear el texto.

Entonces, para mostrar los caracteres en su terminal, no hay otra manera que usar un programa que reemplace el separador de la unidad con algún carácter imprimible.

crater2150
fuente
3

Un poco al margen de las otras (muy buenas) respuestas, si desea alterar solo el carácter de control ^_al mostrar el contenido del archivo, es posible que desee transliterarlo utilizando la trutilidad (y un poco de sintaxis compatible con bash) :

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

Si necesita reemplazar ese carácter de control por su forma "expandida", necesitará en su sedlugar:

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

Tenga en cuenta la sintaxis $'\cX': esta sintaxis informa a su (shell compatible con bash) que reemplace el carácter de control correspondiente. Consulte wikipedia para obtener una lista de alias de caracteres de control utilizando la "notación de intercalación". Si no le gusta esa sintaxis, puede preferir usar la notación octal $'\037'o hexadecimal en su $'\x1f'lugar.

Sylvain Leroux
fuente