剪下命令
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 |