为什么单位分隔符 (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

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

答案1

单位分隔符 ( US) 字符,也称为IS1,属于cntrl字符类,并且是不是在里面print字符类中。它是一个控制字符,用于将文本组织成组,对于旨在利用该信息的程序。一般来说,不可打印的字符在不同的程序或环境中可能会有不同的解释和呈现。

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

您无法在 shell 中获得相同的行为,因为 Unix shell 程序是为了操作纯文本并将纯文本相互传递而编写的。当您cat创建文件时,写入终端的文本必须是文件中实际的内容。

这样就将其留给终端设备来解释该字符。事实证明,一些终端模拟器使US角色与其他角色不同。在gnome-terminal(或任何vte基于 的终端)中,字符将呈现为包含十六进制代码的框001F。在xtermor中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 兼容 shell)替换相应的控制字符。看维基百科的控制字符别名列表使用“插入符号”。如果您不喜欢这种语法,您可能更喜欢使用八进制$'\037'或十六进制$'\x1f'表示法。

相关内容