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

17

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

# 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

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

Дан
источник
Не все символы могут быть напечатаны, разделитель единиц является одним из них. Некоторые редакторы отображают его так, чтобы редактирование стало возможным. Вам нужно перевести его в последовательность печатных символов и, возможно, другого шрифта / цвета, чтобы уменьшить двусмысленность.
ctrl-alt-delor
3
Коды ASCII под 31 и 127 предназначены для того, чтобы заставить терминал или устройство что-то делать (следовательно, они называются управляющими кодами) или обозначать что-то в протоколе (например, EOT или SOH), а не что-то отображать. Он слышит назад, когда терминалы были похожими на пишущие машинки устройствами, и физически требовались такие вещи, как передача телетайпа для возврата каретки. Редакторы могут выбрать их рендеринг с использованием нотации «^», поскольку вы что-то редактируете и не хотите, чтобы терминал фактически выполнял то, что запрашивают управляющие коды.
LawrenceC
1
@LawrenceC: Код 127 на самом деле предназначался для того, чтобы заставить терминал ничего не делать. Если кто-то пробивал ленту и допустил ошибку, он нажимал кнопку, чтобы сделать резервную копию ленты на один пробел, и нажимал «протирать », чтобы пробить все. восемь лунок Когда читатель встречает перфорированный символ, он отправляет его по проводу, но получатель может просто проигнорировать его.
суперкат

Ответы:

19

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

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

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

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

Майк Миллер
источник
Ну, я бы не сказал, USчто совершенно невидим. Когда я вставляю этот символ в терминал с Ctrl+/помощью (подтверждено через <C-v><C-/>), он удаляет непредсказуемое количество текста в строке. Я не до конца понимаю его поведение, но, похоже, он в основном имеет какой-то эффект «обратной табуляции», когда вместо вставки нескольких пробелов он удаляет несколько символов, но иногда он случайным образом вставляет текст, поэтому это сбивает с толку ,
Брэден Бест
10

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

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

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

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

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

crater2150
источник
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' вместо этого или шестнадцатеричные обозначения.

Сильвен Леру
источник