一、概述

cut 命令用于剪切文件的特定部分并将其打印到标准输出,而不更改实际文件。换句话说,它是文本提取工具之一,另外常见的文本提取工具还包括 awk 、sed 、grep 等。

cut 命令常用选项
选项 描述
-c / –characters 剪切特定字符或字符 范围
-b / –bytes 剪切特定字节或字节范围
-f / –fields 指定要提取的字段(例如,-f 2对于第二个字段)
-d / –delimiter 设置字段分隔符(默认为制表符)
–complement 剪切除指定字节、字符或字段之外的所有内容

二、按字符剪切/提取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo cut-command > cut.txt
$ cut -c 2 cut.txt
u
# 提取单个字符,索引以 1 开始

$ cut -c 2-5 cut.txt
ut-c
# 按范围提取多个字符

# 注意,当按范围提取多个字符时,如果是从开头提取,则可以省略掉起始索引,如果省略截止索引,则表明提取到末尾,如下所示:
$ cut -c -3 cut.txt
cut

$ cut -c 5- cut.txt
command

三、按字节剪切/提取

按字节提取与按字符提取类似,当文本为 ASCII 文本文件时,单个字符的大小为 1 个字节,因此可以将上述示例中的 -c 选项替换为 -b 选项,它们的结果是一致的,如下所示:

1
2
3
4
5
6
7
8
$ file cut.txt
cut.txt: ASCII text

$ cut -b 2 cut.txt
u

$ cut -b 2-5 cut.txt
ut-c

如果文本文件使用多字节编码,如 UTF-8 Unicode,那情况就有所不同,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat cut1.txt 
cut-command,张学友上海演唱会

$ cut -b -3,12-14,15-23 cut1.txt
cut,张学友

# utf-8 是变长编码的 unicode 字符集,其英文字母、数字等 ASCII 字符集依旧占用一个字节,
# 但汉字是占用 3 个字节的,上述的','因为是全角字符所以也是占用三个字节,否则只占用一个字节

$ cat cut2.txt
cut-command,张学友上海演唱会

$ cut -b 12,13-21 cut2.txt
,张学友

四、按字段/列提取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ echo "1   2   3" > cut.txt
$ echo "4 5 6" >> cut.txt

$ cut -f 2- cut.txt
2 3
5 6
# 打印第2列与第3列

# 如果列分隔符不是 tab ,则需要使用 -d 选项指定分隔符以覆盖默认行为,如下所示:
$ cat cut.txt
1-2-3-4
5-6-7-8

$ cut -d - -f -2,4 cut.txt
1-2-4
5-6-8

4.2 cut 如何处理多个空格分隔的字段/列
如果是一个空格,则按常规处理,敲一个空格键(需用双引号或单引号括起来),如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cat cut3.txt 
Order-id Date Cost(USD) Details
1 2022-02-20 200 Orange
2 2022-02-21 300 Apple
3 2022-02-22 250 Banana

$ cut -d " " -f 2,3 cut3.txt
Date Cost(USD)
2022-02-20 200
2022-02-21 300
2022-02-22 250
# 提取"日期"与"成本"数据,即第2列与第3列
# 其中 -d " " 可以替换成 -d ' ' ,-f 2,3 可替换成 -f 2-3

如果是三个空格分隔呢?是不是就可以写成

1
2
3
4
5
6
7
$ cat cut2.txt 
Order-id Date Cost(USD) Details
1 2022-02-20 200 Orange
2 2022-02-21 300 Apple
3 2022-02-22 250 Banana

$ cut -d " " -f 2,3 cut2.txt

答案是不行,它会提示你”分隔符必须是单个字符”,所以解决问题的关键是将多个空格转换为单个空格分隔,而 tr 命令则可以将多个相同长度的空格压缩为单个空格,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ tr -s " " < cut2.txt | cut -d " " -f 2,3
Date Cost(USD)
2022-02-20 200
2022-02-21 300
2022-02-22 250
# 如果分别使用1个空格、2个空格和3个空格分隔列,则 tr -s 则不起作用了,
# 此时可以考虑使用 sed 将长短不一的空格替换为单个字符,如下所示:

$ sed 's/\s\+/,/g' cut2.txt
Order-id,Date,Cost(USD),Details
1,2022-02-20,200,Orange
2,2022-02-21,300,Apple
3,2022-02-22,250,Banana
# /g 实现多次替换,否则只替换1处
# \+ 量词,将一个或多个空格替换成单个字符,否则多个空格会替换多次

$ sed 's/\s\+/,/g' cut2.txt | cut -d "," -f 2,3
Date,Cost(USD)
2022-02-20,200
2022-02-21,300
2022-02-22,250

$ sed 's/\s\+/,/g' cut2.txt | cut -d "," --output-delimiter =" " -f 2,3
Date= Cost(USD)
2022-02-20= 200
2022-02-21= 300
2022-02-22= 250


$ sed 's/\s\+/ /g' cut2.txt | cut -d " " -f 2,3
Date Cost(USD)
2022-02-20 200
2022-02-21 300
2022-02-22 250

$ sed 's/ \+/ /g' cut2.txt | cut -d " " -f 2,3
Date Cost(USD)
2022-02-20 200
2022-02-21 300
2022-02-22 250

总结:

  1. 无论是按字符、字节还是字段都可以剪切/提取某一处或多处(用逗号分隔)以及某一范围的内容
  2. 如果是按字段提取多列内容,被提取出的内容,列与列之间也是用 -d 指定的分隔符分隔,除非使用 –output-delimiter 选项额外指定
1
2
3
4
5
6
7
8
9
$ ll -d work
drwxr-xr-x 2 lily lily 4.0K Dec 31 22:12 work

$ ll -d work | cut -c1-10
drwxr-xr-x
# 只看权限部分

$ ll -d work | awk '{print $1, $9}'
drwxr-xr-x work

拖拽更新

手工拖拽方式有个非常大的缺点,那就是每次更新博客都需要重新生成 public,然后重新拖拽上传整个文件夹,比较麻烦。