剪切命令
1.语法差异
上表中的长选项仅受 GNU 版本支持。
没有人物得到特殊待遇
FreeBSD cut
(例如 MacOS 附带)没有 --complement
开关,而在字符范围的情况下,可以使用 colrm
命令:
$ cut --complement -c3-5 <<<"123456789"
126789
$ colrm 3 5 <<<"123456789"
126789
但是,有一个很大的区别,因为 colrm
将 TAB 字符(ASCII 9)视为实际制表,直到下一个八的倍数,退格(ASCII 8)为 -1 宽; 相反,cut
将所有字符视为一列宽。
$ colrm 3 8 <<<$'12\tABCDEF' # Input string has an embedded TAB
12ABCDEF
$ cut --complement -c3-8 <<<$'12\tABCDEF'
12F
3.(仍然没有)国际化
设计 cut
时,所有字符都是一个字节长,国际化不是问题。当编写具有更宽字符的系统变得流行时,POSIX 采用的解决方案是在旧的 -c
开关之间进行定位,这应该保留其选择字符的含义*,无论宽度多少,并引入一个新的开关 -b
,它应该选择字节,*不管当前的字符编码。在大多数流行的实现中,-b
被引入并且可以工作,但是 -c
仍然像 -b
一样工作而不是它应该的。例如,使用 GNU cut
:
似乎 SE 的垃圾邮件过滤器将带有孤立汉字字符的英文文本列入黑名单。我无法克服这个限制,因此以下示例的表现力不如它们。
# In an encoding where each character in the input string is three bytes wide,
# Selecting bytes 1-6 yields the first two characters (correct)
$ LC_ALL=ja_JP.UTF-8 cut -b1-6 kanji.utf-8.txt
...first two characters of each line...
# Selecting all three characters with the -c switch doesn’t work.
# It behaves like -b, contrary to documentation.
$ LC_ALL=ja_JP.UTF-8 cut -c1-3 kanji.utf-8.txt
...first character of each line...
# In this case, an illegal UTF-8 string is produced.
# The -n switch would prevent this, if implemented.
$ LC_ALL=ja_JP.UTF-8 cut -n -c2 kanji.utf-8.txt
...second byte, which is an illegal UTF-8 sequence...
如果你的字符超出 ASCII 范围并且你想使用 cut
,则应始终注意编码中的字符宽度并相应地使用 -b
。如果和当 -c
按照文档开始工作时,你将不必更改脚本。
4.速度比较
cut
的局限性使人们怀疑它的用处。事实上,更强大,更受欢迎的实用程序可以实现相同的功能。然而,cut
的优势在于其性能。请参阅下面的一些速度比较。test.txt
有 300 万行,每行有 5 个空格分隔的字段。对于 awk
测试,使用了 mawk
,因为它比 GNU awk
快。shell 本身(最后一行)是目前表现最差的。给出的时间(以秒为单位)是 time
命令给出的实时时间。
(只是为了避免误解:所有测试的命令都给出了与给定输入相同的输出,但它们当然不等同,并且在不同情况下会给出不同的输出,特别是如果字段由可变数量的空格分隔)
命令 | 时间 |
---|---|
cut -d ' ' -f1,2 test.txt |
1.138s |
awk '{print $1 $2}' test.txt |
1.688s |
join -a1 -o1.1,1.2 test.txt /dev/null |
1.767s |
perl -lane 'print "@F[1,2]"' test.txt |
11.390s |
grep -o '^\([^ ]*\) \([^ ]*\)' test.txt |
22.925s |
sed -e 's/^\([^ ]*\) \([^ ]*\).*$/\1 \2/' test.txt |
52.122s |
while read a b _; do echo $a $b; done <test.txt |
55.582s |