cut 命令详解与参数实测(Ubuntu 22.04)

cut 命令逐参数实测:-d/-f 取列与区间、-c/-b 字符字节截取与多字节截断、--complement 与 --output-delimiter,全部回显在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文本处理2026/10/15

cut 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 GNU cut 的字段与位置截取能力——-d/-f 按分隔符取列(含多列、区间、开区间)、-c/-b 按字符与字节位截取、--complement 反选、--output-delimiter 自定义输出分隔符,以及多字节截断与整行输出等关键行为,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

一、环境信息

本节记录实测环境与测试数据,便于读者按相同条件复现本文全部命令与回显。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • cut 版本:GNU coreutils 8.32(cut --version 实测)
  • 默认 locale:LANG 未设置(等效 C locale),多字节演示显式指定 C.UTF-8
  • 实测工作目录:/root/demo/cut/
  • 测试数据:users.csv(4 列 CSV 员工表)、cols.txt(3 行定宽文本)、names_zh.txt(2 行中文 UTF-8 样例)

二、命令概览

2.1 语法与测试数据准备

cut 的基本语法为 cut OPTION... [FILE]...:从每个 FILE(或标准输入)的每一行中选出指定的字节、字符或字段并输出,-b、-c、-f 三者必须且只能选用其一。测试前先准备一套演示文件,后续所有参数实测都基于这套数据:

mkdir -p /root/demo/cut

cat > /root/demo/cut/users.csv <<'EOF'
name,dept,age,city
alice,dev,28,Beijing
bob,ops,32,Shanghai
carol,dev,26,Shenzhen
dave,qa,30,Guangzhou
EOF

cat > /root/demo/cut/cols.txt <<'EOF'
1234567890
abcdefghij
ABCDEFGHIJ
EOF

cat > /root/demo/cut/names_zh.txt <<'EOF'
你好世界
早上好晚安
EOF

验证数据就绪:

$ ls -l /root/demo/cut
total 12
-rw-r--r-- 1 root root  33 Oct 15 07:40 cols.txt
-rw-r--r-- 1 root root  29 Oct 15 07:40 names_zh.txt
-rw-r--r-- 1 root root 103 Oct 15 07:40 users.csv

$ cat /root/demo/cut/names_zh.txt
你好世界
早上好晚安

$ echo LANG=$LANG
LANG=

💡 说明:names_zh.txt 中每个汉字占 3 个 UTF-8 字节,这两行分别为 13、16 字节(含换行符),3.7 节将用它实测字节截断现象。

2.2 --help 全量回显

cut --help 输出全部参数清单(实测原样保留,可作为参数速查):

Usage: cut OPTION... [FILE]...
Print selected parts of lines from each FILE to standard output.

With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -b, --bytes=LIST        select only these bytes
  -c, --characters=LIST   select only these characters
  -d, --delimiter=DELIM   use DELIM instead of TAB for field delimiter
  -f, --fields=LIST       select only these fields;  also print any line
                            that contains no delimiter character, unless
                            the -s option is specified
  -n                      (ignored)
      --complement        complement the set of selected bytes, characters
                            or fields
  -s, --only-delimited    do not print lines not containing delimiters
      --output-delimiter=STRING  use STRING as the output delimiter
                            the default is to use the input delimiter
  -z, --zero-terminated    line delimiter is NUL, not newline
      --help     display this help and exit
      --version  output version information and exit

Use one, and only one of -b, -c or -f.  Each LIST is made up of one
range, or many ranges separated by commas.  Selected input is written
in the same order that it is read, and is written exactly once.
Each range is one of:

  N     N'th byte, character or field, counted from 1
  N-    from N'th byte, character or field, to end of line
  N-M   from N'th to M'th (included) byte, character or field
  -M    from first to M'th (included) byte, character or field

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/cut>
or available locally via: info '(coreutils) cut invocation'

💡 说明:帮助中的 LIST 语法是 cut 的核心——N 取第 N 项、N- 从第 N 项到行尾、N-M 闭区间、-M 从行首到第 M 项,多项用逗号组合;同时明确 -b、-c、-f 三选一,不能同时使用。

2.3 版本确认

$ cut --version | head -1
cut (GNU coreutils) 8.32

三、参数逐项实测

本章逐项实测每个参数:每节先给命令与真实回显,再解释行为要点。

3.1 -d 与 -f:按分隔符取列

-d 指定分隔符(默认是制表符 TAB),-f 指定取第几列。取 users.csv 的第 1 列(姓名):

$ cut -d, -f1 /root/demo/cut/users.csv
name
alice
bob
carol
dave

逗号被当作字段分隔符,每行第 1 个逗号前的内容被输出。-d, 中的逗号紧跟参数即可,也可以写成 -d ',',效果相同。

3.2 -f 的列清单与区间:多列、范围与开区间

-f 支持 2.2 节帮助中的全部 LIST 语法,五种写法一次看全:

$ cut -d, -f1,3 /root/demo/cut/users.csv
name,age
alice,28
bob,32
carol,26
dave,30

$ cut -d, -f2-4 /root/demo/cut/users.csv
dept,age,city
dev,28,Beijing
ops,32,Shanghai
dev,26,Shenzhen
qa,30,Guangzhou

$ cut -d, -f3- /root/demo/cut/users.csv
age,city
28,Beijing
32,Shanghai
26,Shenzhen
30,Guangzhou

$ cut -d, -f-2 /root/demo/cut/users.csv
name,dept
alice,dev
bob,ops
carol,dev
dave,qa
  • f1,3:逗号列出多个不连续列,输出顺序按行内原始顺序(不是 LIST 书写顺序);
  • f2-4:闭区间取第 2 到第 4 列;
  • f3-:开区间,第 3 列直到行尾;
  • f-2:从第 1 列到第 2 列。

再看越界行为——取不存在的第 5 列:

$ cut -d, -f5 /root/demo/cut/users.csv



输出为 6 个空行(每行输入对应一个空输出行)。cut 对超出该行列数的字段不报错,静默输出空内容。

💡 提示:「输出顺序按行内原始顺序」意味着 cut -d, -f3,1 的输出仍是 第1列,第3列,无法用它交换列顺序,交换列应使用 awk。

3.3 -d 未命中分隔符:整行输出

当一行中不存在 -d 指定的分隔符时,cut 默认把整行原样输出:

$ echo 'no-delimiter-here' | cut -d, -f1
no-delimiter-here

$ grep alice /root/demo/cut/users.csv | cut -d: -f1
alice,dev,28,Beijing

第一条的输入没有逗号,整行原样输出;第二条用冒号当分隔符去解析逗号 CSV,行内没有冒号,同样整行输出。这是 cut 最经典的「坑」:分隔符选错时不会报错,而是把所有行原样放行。

💡 提示:过滤这种行可加 -s(--only-delimited,丢弃不含分隔符的行,见 2.2 节帮助原文);排查「cut 似乎没生效」时,先确认分隔符与数据是否匹配。

3.4 --output-delimiter:自定义输出分隔符

多列输出的默认分隔符沿用输入分隔符,可用 --output-delimiter=STRING 改为任意字符串:

$ cut -d, --output-delimiter=' | ' -f1,3 /root/demo/cut/users.csv
name | age
alice | 28
bob | 32
carol | 26
dave | 30

$ cut -d, --output-delimiter=@ -f1,4 /root/demo/cut/users.csv
name@city
alice@Beijing
bob@Shanghai
carol@Shenzhen
dave@Guangzhou

输出分隔符支持多字符字符串(如 |),而输入分隔符 -d 只接受单个字符。

3.5 --complement:反选字段

反选输出「未选中」的部分,适合「排除某一列」的场景:

$ cut -d, --complement -f2 /root/demo/cut/users.csv
name,age,city
alice,28,Beijing
bob,32,Shanghai
carol,26,Shenzhen
dave,30,Guangzhou

选中集为「除第 2 列外的全部列」,等价于手写 -f1,3-4。列数多时反选比逐个列举更稳。

3.6 -c:按字符位截取

-c 按字符位置截取,位置从 1 计数。对定宽文件 cols.txt 实测:

$ cut -c 1-3 /root/demo/cut/cols.txt
123
abc
ABC

$ cut -c 5 /root/demo/cut/cols.txt
5
e
E

$ cut -c 1-3,8- /root/demo/cut/cols.txt
123890
abchij
ABCHIJ

c1-3 取每行前 3 个字符,c5 只取第 5 个字符,c1-3,8- 组合了区间与开区间,输出顺序同样按行内原始顺序拼接。

💡 技术拓展:Linux 下按列/字段切分文本有三个主流工具,选型取决于数据形态:

工具切分依据适用场景
cut单字符分隔符字段 / 固定字节字符位格式规整的 CSV、passwd、定宽日志,轻量最快
awk默认连续空白,可自定义 FS多空格对齐文本、需要计算/重排/过滤
sed正则匹配替换复杂模式提取,正则能力强

本文主角 cut 胜在简单直接;遇到多空格分隔或需要交换列序时换 awk(如 awk '{print $2, $1}')。

3.7 -b:按字节位截取与多字节截断现象

-b 按字节位置截取。UTF-8 中每个汉字占 3 字节,用 names_zh.txt 实测截断现象:

$ cut -b 1-3 /root/demo/cut/names_zh.txt
你
早

$ cut -b 1-6 /root/demo/cut/names_zh.txt
你好
早上

$ cut -b 1-4 /root/demo/cut/names_zh.txt | od -An -tx1
 e4 bd a0 e5 0a e6 97 a9 e4 0a

b1-3 恰好取到「你」的 3 个完整字节,所以显示正常;b1-6 是两个汉字;而 b1-4 多取了第 4 个字节——od 的十六进制回显 e4 bd a0 e5 说明这是「你」的 3 字节加「好」的首字节,屏幕上会显示为乱码。可见 -b 完全按字节切,多字节字符会被拦腰截断。

再看 -c 在多字节下的真实表现(显式 UTF-8 locale),并用 od 检查实际输出字节:

$ LANG=C.UTF-8 cut -c 1-2 /root/demo/cut/names_zh.txt | od -An -tx1
 e4 bd 0a e6 97 0a

$ cut -c 1-2 /root/demo/cut/names_zh.txt | od -An -tx1
 e4 bd 0a e6 97 0a

两条输出完全一致:都是每个汉字的前 2 个字节加换行符(0a)。也就是说在 GNU coreutils 8.32 的实现中,-c 实际按字节处理,与 -b 行为相同,本环境直接显示该输出同样得到乱码。

💡 提示:在 coreutils 8.32 中不要指望 cut -c 处理多字节字符。中文按「字符」截取请使用 awk:awk '{print substr($0, 1, 2)}'(C.UTF-8 下按字符计),或先转码再处理。

3.8 解析 /etc/passwd 实战

/etc/passwd 每行 7 个冒号分隔字段(用户名:密码占位:UID:GID:描述:家目录:shell),是 cut 的招牌场景:

$ cut -d: -f1 /etc/passwd | head -6
root
daemon
bin
sys
sync
games

$ grep bash$ /etc/passwd | cut -d: -f1,7
root:/bin/bash

$ cut -d: -f1,3-4 /etc/passwd | head -5
root:0:0
daemon:1:1
bin:2:2
sys:3:3
sync:4:65534

第 1 条列出系统用户名;第 2 条先 grep 筛出 shell 为 bash 的行,再用 cut 取「用户名:shell」;第 3 条组合单列与区间取 UID 与 GID。先 grep 过滤再 cut 截列,是日志与配置文件处理的通用套路。

四、实战示例

前面各节覆盖了单个参数的行为,本节给三个可直接套用的组合场景。

1. CSV 提取指定列并美化输出——取姓名与年龄列,输出分隔符换成竖线便于阅读:

$ cut -d, --output-delimiter=' | ' -f1,3 /root/demo/cut/users.csv
name | age
alice | 28
bob | 32
carol | 26
dave | 30

2. 统计系统有哪些用户——-d: 配合 head 控制输出规模:

$ cut -d: -f1 /etc/passwd | head -6
root
daemon
bin
sys
sync
games

3. 找出可交互登录的账户——grep 定位 bash shell 行,cut 提取关键字段:

$ grep bash$ /etc/passwd | cut -d: -f1,7
root:/bin/bash

五、注意事项与常见问题

本节汇总 cut 使用中最容易踩坑的四个问题,均对应前文实测结论。

Q1:cut -c 取中文为什么是乱码?

GNU coreutils 8.32 的 cut 是字节导向实现,-c 与 -b 实测行为一致(3.7 节 od 字节对照),多字节汉字会被从中间截断。中文按字符截取改用 awk 的 substr(),或用 sed 正则处理。

Q2:「cut 似乎没生效」、输出原样不动是怎么回事?

十有八九是 -d 分隔符与数据不匹配。cut 对不含分隔符的行默认整行输出、不报错(3.3 节实测),CSV 数据用冒号解析时就会全部原样放行。排查顺序:先确认分隔符字符正确,再用 -s 丢弃不含分隔符的行快速定位异常行。

Q3:cut -d 能用多字符分隔符吗?

不能,-d 只接受单个字符;需要按多字符字符串切分时改用 awk(awk -F'、')或先用 tr/sed 把多字符分隔符替换成单字符再交给 cut。输出方向则没有这个限制,--output-delimiter 支持任意长度字符串(3.4 节实测)。

Q4:取不存在的列会报错吗?

不会。越界字段(如 4 列文件取 -f5)静默输出空行(3.2 节实测),整表取不到数据时输出全空,容易误判为「文件是空的」。遇到空输出先核对列数:head -1 文件 或 awk -F',' '{print NF; exit}' 查看实际列数。

六、参考链接