为什么在终端输出中看不到单位分隔符(ASCII 31)?


17

单位分隔符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

但这很麻烦。在Bash shell中打印到stdout时,为什么单位分隔符没有可见的表示形式?我什至无法正确复制并粘贴shell输出;单元分隔符在此过程中会丢失。


并非所有字符都可以打印,单位分隔符是其中之一。一些编辑器将以某种方式显示它以使编辑成为可能。您需要将其转换为可打印的字符序列,并可能将其转换为不同的字体/颜色,以减少歧义。
ctrl-alt-delor 2014年

3
31和127以下的ASCII码旨在使终端或设备执行某项操作(因此将其称为控制代码),或者代表协议中的某项内容(例如EOT或SOH),而不是显示某些内容。当终端是类似于打字机的设备时,它就会回弹,实际上需要告诉电传打字机回车。编辑者可以选择使用“ ^”表示法来渲染它们,因为您正在编辑某些内容,并且不希望终端实际执行控制代码所要求的内容。
LawrenceC 2014年

1
@LawrenceC:代码127实际上旨在使终端不执行任何操作,如果有人在打孔磁带时出错,则可以按一个按钮将磁带备份一格,然后按“擦掉”,以打孔所有八个洞。当阅读器遇到全打孔字符时,它将通过电线发送它,但是接收者可以忽略它。
超级猫

Answers:


19

单位分隔符(US)字符,也被称为IS1,在cntrl字符类,并且是print字符类。它是一个控制字符,用于将文本组织成组,用于设计为使用该信息的程序。通常,不可打印字符可能会在不同程序或环境中被不同地解释和呈现。

之所以^_在Vim 中看到它,是因为Vim是一个交互式编辑器。只要将正确的二进制字符写入磁盘,它就可以随意渲染不可打印的字符。

您无法在shell中获得相同的行为,因为Unix shell程序被编写为可在它们之间进行操作并相互传递纯文本。当您cat创建文件时,写入终端的文本必须是文件中实际存在的文本。

这样就将其留给终端设备来解释字符。事实证明,某些终端仿真器的渲染字符确实US与其他仿真器不同。在gnome-terminal(或任何vte基于终端的终端)中,字符将被渲染为包含十六进制代码的框001F。在xtermrxvt,字符确实是不可见的。


好吧,我不会说这US完全看不见的。当我使用Ctrl+/(通过确认<C-v><C-/>)将该字符插入终端时,它将删除行中不可预测的文本量。我还不完全了解它的行为,但它似乎主要具有某种“反向制表符”的效果,它不是插入许多空格,而是删除了许多字符,但有时却随机插入了文本,因此令人困惑。
Braden Best,

10

单位分隔符在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兼容的shell)替换相应的控制字符。有关使用“插入符号” 的控制字符别名的列表,请参见Wikipedia。如果您不喜欢这种语法,则可能更喜欢使用八进制$'\037'或十六进制$'\x1f'表示法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.