为什么在命令 cut 中解释字符串中的字符“£”很奇怪?

Pet*_*amm 19 command-line utf-8 cut-command

我正在开发一个 bash 脚本并提出了以下奇怪的行为!

$ echo £ |cut -c 1
?
Run Code Online (Sandbox Code Playgroud)

符号£传递给下一个命令,cut其过滤器仅选择一个字符。

当我修改cut命令中的过滤器以选择 2 个字符时,则£通过!

$ echo £ |cut -c 1-2
£
Run Code Online (Sandbox Code Playgroud)

不是一个严重的问题,我在脚本中有一个解决方法,但是为什么在选择£标志时 cut 命令中的过滤器需要 2 个位置而不是 1 个位置?

Fed*_*eli 43

cutUbuntu 中的命令不支持多字节字符。 对于此版本的命令,字符与字节相同cut

井号 ( £) 是一个 UTF-8 字符,由两个字节 (c2a3) 组成:

$ echo £ | od -t x1
0000000 c2 a3 0a
0000003
Run Code Online (Sandbox Code Playgroud)

:该0a字符为“换行符”(ASCII“换行符”字符)。

当您cut选择该行的第一个字符时,您只选择了 的c2一部分£,这不是有效的 UTF-8 字符。结果你会在屏幕上看到奇怪的问号?替换字符):

$ echo £ | cut -c 1 | od -t x1
0000000 c2 0a
0000002
Run Code Online (Sandbox Code Playgroud)

注意:以上是在最新版本的cutUbuntu 20.10(GNU coreutils 版本 8.32)上测试的。

如果要选择多字节字符,可以使用grepGNU grep version 3.4)命令,如下所示:

$ echo x£? | grep -o '^.'
x
$ echo x£? | grep -o '^..'
x£
$ echo x£? | grep -o '^...'
x£?
Run Code Online (Sandbox Code Playgroud)

在评论的帮助下,这个答案得到了改进。

  • @marcelm 一些 `cut` 实际上确实区分了 `-b` 和 `-c`。我的 `cut (GNU coreutils) 8.32` 在 UTF-8 语言环境中使用 `-c` 做正确的事情,但事实证明这是由于下游 Fedora 补丁造成的。上游 coreutils 目前仍将 `-b` 和 `-c` 作为同一事物的别名处理。 (7认同)
  • 请注意,这个奇怪的问号在 Unicode 中被称为替换字符。当字符或字节无法转换为当前选择的编码中的 Unicode 代码点时,正式应该使用它(并且在某些情况下,它也可能用于表示当前字体不包含字形的字符)。 (3认同)
  • _“`cut` 命令不能识别多字节字符。”_ - 有趣的是,(GNU) cut 有两种选择字节(`-b`)和选择字符(`-c`)的选项。人们希望它知道如何处理多字节字符然后...... (2认同)
  • 最初我是这样做的 @GrzegorzOledzki 。但是,由于第二个带有 `cut` 的示例已经有了它,为了保持一致性,我删除了第一个示例中的 `-n`。 (2认同)
  • @marcelm,[`cut` 被指定为具有 `-b` 和 `-c`](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/cut.html)。GNU 实现 [只是将它们视为相同](https://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/cut.c;h=0f6ba602c207018721414459e0c2df18d15dd190;hb= 8d13292a73ecf1f265f77731d3ace29866e3d616#l503)... (2认同)

Rav*_*ina 18

在 UTF-8 编码中,£is的十六进制值0xC2 0xA3 (c2a3)11000010 10100011二进制的。

所以它是两个字节(就像两个字符)。cut -c将每个字节视为产生?.


$ echo -n £ | xxd
00000000: c2a3                                     ..

$ echo -n £ | wc --bytes
2
Run Code Online (Sandbox Code Playgroud)

  • UTF-8 最多可以有 4 个字节,这不是很直观。这是一个问题,因为它包含 7 位 ASCII 但对其进行了扩展。 (3认同)
  • 需要明确的是,GNU cut 将每个字节视为一个带有 -c 的字符——其他版本的 cut 将正确处理字符。 (2认同)