Почему разделитель единиц измерения (ASCII 31) не виден в выходных данных терминала?

Почему разделитель единиц измерения (ASCII 31) не виден в выходных данных терминала?

Символ разделителя единиц ASCII (ASCII 31, восьмеричный 37) виден в Vim как ^_. Но если я распечатаю тот же файл на терминале, символ будет невидим. Это приводит к тому, что поля в строке слипаются:

# 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

Полагаю, что я могу сделать разделитель единиц измерения видимым с помощью cat -v:

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

Но это довольно громоздко. Почему разделитель единиц измерения не имеет видимого представления при печати в stdout в оболочке Bash? Я даже не могу правильно скопировать и вставить вывод оболочки; разделитель единиц измерения теряется в процессе.

решение1

Символ разделителя единиц ( US), также известный как IS1, относится к cntrlклассу символов и являетсянетв printклассе символов. Это управляющий символ, который предназначен для организации текста в группы,для программ, которые предназначены для использования этой информации. В общем случае непечатаемые символы, вероятно, будут интерпретироваться и отображаться по-разному в разных программах или средах.

Причина, по которой вы видите его представленным ^_в Vim, заключается в том, что Vim — интерактивный редактор. Он может свободно отображать непечатаемые символы так, как ему хочется, пока правильный двоичный символ записан на диск.

Вы не можете получить то же самое поведение в оболочке, потому что программы оболочки Unix написаны для работы с открытым текстом и передачи его друг другу. Когда вы открываете catфайл, текст, который записывается на терминал, должен быть тем, что на самом деле находится в файле.

Так что это оставляет на усмотрение терминального устройства интерпретировать символ. И оказывается, что некоторые эмуляторы терминаладелатьвизуализирует USсимвол иначе, чем другие. В gnome-terminal(или любом vteтерминале на основе -) символ будет визуализироваться как поле, содержащее шестнадцатеричный код 001F. В xtermили rxvtсимвол действительно невидим.

решение2

Разделитель единиц находится в диапазоне ASCIIУправляющие символы, и поэтому не имеет (или обычно не должен иметь) визуального представления.

Vim и некоторые другие редакторы отображают их, так что вы можете их редактировать. Как вы заметили, cat -vотображает его тоже. На странице руководства показано, что -vэто короткая форма --show-nonprinting, которая заставляет его заменять непечатаемые символы на печатное представление, которое не является исходным содержимым файла и поэтому может вызвать проблемы, если вывод фактически осуществляется в другую программу.

Представление, которое вы видите, уже намекает, что это управляющий символ: символ с префиксом a ^является общепринятой нотацией для Ctrl+ символа, который является комбинацией клавиш, которая создает этот символ в терминале. Ctrl+ _позволит вам ввести разделитель единиц в vim, например. Но другой редактор или какой-либо просмотрщик GUI может отображать шестнадцатеричный код, заполнитель или что-то совершенно иное.

Поскольку ваш терминал не печатает управляющие символы, они также не копируются при выделении текста (исключением являются пробельные символы, такие как новая строка и табуляция, которые также являются управляющими символами). Другим примером управляющих символов в терминале, которые обычно игнорируются при копировании, являются цветовые коды, представляющие собой символ, ESCза которым следует код для раскрашивания текста.

Таким образом, чтобы отобразить символы на вашем терминале, нет другого способа, кроме как использовать программу, которая заменяет разделитель единиц измерения каким-либо печатным символом.

решение3

Немного на грани других (очень хороших) ответов, если вы хотите изменитьтолькоуправляющий символ ^_при отображении содержимого файла, вы можете захотетьтранслитерироватьс помощью trутилиты (и немного синтаксиса, совместимого с bash):

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

Если вам необходимо заменить этот управляющий символ его «расширенной» формой, вам понадобится sed:

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

Обратите внимание на синтаксис $'\cX': этот синтаксис информирует вашу (совместимую с bash оболочку) о необходимости замены соответствующего управляющего символа. Смотритевикипедия для списка псевдонимов управляющих символовс использованием "обозначения с кареткой". Если вам не нравится такой синтаксис, вы можете предпочесть использовать восьмеричную $'\037'или шестнадцатеричную $'\x1f'запись.

Связанный контент