该命令cut
有一个选项-c
可以处理字符,而不是带有选项的字节-b
。但这似乎不起作用,在en_US.UTF-8
语言环境中:
第二个字节给出第二个 ASCII 字符(在 UTF-8 中编码方式相同):
$ printf 'ABC' | cut -b 2
B
但不给出 UTF-8 语言环境中三个希腊非 ASCII 字符中的第二个:
$ printf 'αβγ' | cut -b 2
�
没关系 - 这是第二个字节。
那么我们看第二个特点反而:
$ printf 'αβγ' | cut -c 2
�
那看起来破了。
经过一些实验,结果发现范围3-4
显示了第二个字符:
$ printf 'αβγ' | cut -c 3-4
β
但这与字节 3 到 4 相同:
$ printf 'αβγ' | cut -b 3-4
β
所以-c
并不比-b
UTF-8 更重要。
我预计区域设置不适合 UTF-8,但相比之下,wc
可以按预期工作;
常用于计算字节数,带有选项-c
( --bytes
)。
(请注意令人困惑的选项名称。)
$ printf 'αβγ' | wc -c
6
但它也可以使用选项-m
( --chars
) 来计算字符数,这样就可以了:
$ printf 'αβγ' | wc -m
3
所以我的配置似乎没问题 - 但有一些特别之处cut
。
也许它根本不支持UTF-8?但它似乎确实支持多字节字符,否则就不需要支持-b
和-c
。
那么,出了什么问题呢?为什么?
据我所知,区域设置看起来适合 utf8:
$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
输入,逐字节:
$ printf 'αβγ' | hd
00000000 ce b1 ce b2 ce b3 |......|
00000006
答案1
你还没有说cut
你正在使用哪一个,但既然你提到了 GNU long 选项,--characters
我就假设它就是那个。在这种情况下,请注意这一点段落来自info coreutils 'cut invocation'
:
‘-c character-list’ ‘--characters=character-list’
选择仅打印字符列表中列出的位置中的字符。
-b
和现在一样,但国际化将改变这一点。
(强调已添加)
目前,GNUcut
始终按照单字节“字符”工作,因此您看到的行为是预期的。
同时支持-b
和-c
选项是POSIX 要求— 它们没有被添加到 GNU 中,cut
因为它具有多字节支持并且它们可以正常工作,但为了避免在 POSIX 兼容输入上出现错误。-c
在其他一些实现中也做了同样的事情cut
,尽管不是自由BSD'沙操作系统至少是。
这是历史行为的-c
。-b
新添加的内容是为了接管字节角色,以便-c
可以处理多字节字符。也许几年后它就能一直按预期工作,尽管进展并不快(已经十多年了)。 GNUcut
甚至没有实现该-n
选项然而,尽管它是正交的并且旨在帮助过渡。旧脚本存在潜在的兼容性问题,这可能是一个问题,尽管我不确定原因是什么。
答案2
colrm
( 的一部分util-linux
,应该已经安装在大多数发行版上)似乎可以更好地处理国际化:
$ echo 'αβγ' | colrm 3
αβ
$ echo 'αβγ' | colrm 2
α
注意编号:colrm N
将从中删除列N
,最多打印字符N-1
。
(学分)
答案3
由于许多grep
实现都是多字节感知的,因此您还可以使用grep -o
它来模拟cut -c
.
前两个字符:
$ echo Τηεοδ29 | grep -o '^..'
Τη
最后三个字符:
$ echo Τηεοδ29 | grep -o '...$'
δ29
第二个字符:
$ echo Τηεοδ29 | grep -o '^..' | grep -o '.$'
η
调整句点数量或使用{x,y}
语法来模拟cut
范围。
答案4
八年多后,我无法重现OP的问题(MacOS 13.4 Ventura):
~$ printf 'ABC' | cut -b 2
B
~$ printf 'αβγ' | cut -b 2
�
~$ printf 'αβγ' | cut -c 2
β
~$ printf 'αβγ' | cut -c 3-4
γ
~$ printf 'αβγ' | cut -b 3-4
β
~$ printf 'αβγ' | wc -c
6
~$ printf 'αβγ' | wc -m
3
以上似乎是OP所希望的答案?请注意,行结尾cut -c 3-4
实际上返回γ%
到 下zsh
,表示部分行(请求的字符数多于可返回的字符数)。
-$ man cut
没有给我除macOS 13.4 August 3, 2017
IEEE Std 1003.2-1992 (“POSIX.2”) 以外的版本,并带有附加-w
标志作为规范的扩展。“历史:AT&T System III UNIX 中出现了 cut 命令。”