第4章 文本处理工具

4.1 sort 排序文本

sort:按行对文本排序;把每行当作记录,空白/指定字符切分成字段
⚠重点坑:排序结果受 locale(语言区域)影响;脚本稳定排序建议:LC_ALL=C sort 使用原始ASCII字节排序。

常用选项汇总

选项 说明
-b 忽略行开头空白
-C 仅检查是否有序,不输出,用退出码判断结果
-d 字典序,只看字母数字空格,忽略标点
-f 忽略大小写
-g GNU扩展,浮点数排序,不可移植
-i 忽略不可打印字符
-k 指定排序键(字段、字符区间)
-m 输入已经有序,只做合并,不重新排序
-n 整数数值排序,不是ASCII字符比较
-o file 输出写入文件,可以直接覆盖输入文件(安全,内部用临时文件)
-r 反转,降序从大到小
-t 字符 设置字段分隔符,只能单个字符;默认空白分割
-u 去重:只对比排序键,键相同就丢弃,不对比整行全部内容

重要:sort a.txt > a.txt 错误!会直接清空源文件;覆盖文件请用 sort -o a.txt a.txt

-k 排序键用法(高频)

  1. -kN:从第N字段开始,一直到行末尾结束(不是到本字段末尾)
  2. -kN,M:从第N字段开始,到第M字段结束(推荐写,边界明确)
  3. 修饰符直接跟在数字后面:n数字、r逆序、f忽略大小写
  4. 多个‑k代表多条件排序:第一个条件相同才比对下一个条件。

示例文件 /etc/passwd,冒号:分隔字段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 按第1字段(用户名)排序,只使用第1列做key
sort -t: -k1,1 /etc/passwd

# 按第3字段UID,数字降序
sort -t: -k3nr,3 /etc/passwd

# 多条件:先第4列GID升序,再第3列UID升序
sort -t: -k4n -k3n /etc/passwd

# -u 去重,GID相同只保留第一条记录
sort -t: -k4n -u /etc/passwd

多行记录块排序(记录之间空行分隔)

场景:一条数据占多行,记录之间用空行隔开,不能直接‑k。 思路:

  1. 把块内换行替换成一个特殊标记字符,整条记录变成单行
  2. sort排序
  3. 再把标记还原回换行
1
2
3
4
5
cat my‑friends |
awk -v RS="" '{ gsub("\n", "~Z"); print }' |
sort -f |
awk -v ORS="\n\n" '{ gsub("~Z", "\n"); print }' |
grep -v '# SORTKEY'
  • RS="":awk输入记录分隔符,空行代表记录分割
  • ORS="\n\n":输出记录之间输出空行
  • gsub():全局字符串替换

sort稳定性

稳定排序:排序键相等,保留原始输入的先后顺序。

POSIX不要求sort稳定;GNU sort加参数 --stable 开启稳定排序。

sort小结

  1. 脚本固定 LC_ALL=C sort,消除不同系统locale带来排序结果差异。
  2. -n整数;‑g浮点数GNU独有,跨平台不要用。
  3. 覆盖文件使用 -o,不要重定向>源文件
  4. -u只对比排序键,不是整行去重。

4.2 uniq 删除重复行

⚠关键:uniq只消除相邻连续的重复行!分散的重复识别不到。
标准用法:sort | uniq,先排序让相同行挨在一起。

选项 作用
-c 统计重复次数,输出「计数 内容」
-d 只输出出现过重复的行
-u 只输出只出现一次、没有重复的行

示例

1
2
3
4
5
6
7
8
latin‑numbers:

tres
unus
duo
tres
duo
tres
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 去重
sort latin‑numbers | uniq

duo
tres
unus

# 统计每行出现多少次
sort latin‑numbers | uniq -c

2 duo
3 tres
1 unus

# 只打印重复行
sort latin‑numbers | uniq -d

duo
tres

# 只打印仅出现一次的行
sort latin‑numbers | uniq -u

unus

sort -u VS sort | uniq

  • sort -u:对比排序键;
  • sort | uniq:对比整行全部内容。想要完整行去重,优先管道uniq。

4.3 fmt 段落重排格式化

把长文本折行,控制每行宽度;不属于POSIX标准,老旧UNIX不一定有

选项 说明
‑s 只拆分超长行;短行不会互相合并
‑w N 设置输出行宽度,默认约75字符(GNU)

示例

1
2
3
4
5
6
7
This is a very long line that contains many english words for testing fmt command function.
short line one
short line two
another very long sentence here we go test test test test test test test
a
b
c
 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
# 宽度30字符
fmt -w 30 test.txt

This is a very long line that
contains many english words
for testing fmt command
function.  short line one
short line two
another very long sentence
here we go test test test
test test test test
a b c

# 只拆长行,不合并短行
fmt -s -w 10 <<END
one two three four five
six
seven
eight
END

one two
three
four five
six
seven
eight

可移植脚本尽量避免fmt,各个系统参数行为差异很大。

4.4 wc 统计:行数、单词、字节/字符

默认输出顺序:行数 单词数 字节数

选项 作用
‑l 统计行数
‑w 统计单词(空白分割)
‑c 统计字节数
‑m 统计字符数,适合UTF‑8多字节中文
1
2
3
4
5
6
echo Testing one two three | wc -l
echo Testing one two three | wc -w
echo Testing one two three | wc -c

# 多个文件统计,最后输出total合计
wc /etc/passwd /etc/group

统计行为受 LC_CTYPE 语言环境影响。

4.5 打印相关工具

两套历史打印体系:Berkeley 与 System V

操作 Berkeley System V
打印文件 lpr lp
取消任务 lprm cancel
查看队列 lpq lpstat -o

环境变量:

  • Berkeley:PRINTER 指定打印机
  • System V:LPDEST 指定打印机

pr:打印预处理分页工具

pr不直接打印;做分页、加页眉、多栏格式化,输出交给lp/lpr。

常用选项

选项 说明
‑c n / -n 输出n列多栏
‑f 分页符,分页
‑h "文本" 自定义页眉,替换默认文件名时间
‑l n 每页行数
‑o n 整体向右偏移n个空格
‑t 关闭页眉页脚
‑w N 设置行宽度

示例:5栏输出,关闭页眉

1
sed -n -e 19000,19025p /usr/dict/words | pr -c5 -t

4.6 head / tail 截取开头结尾

head:取文件前面若干行

1
2
3
head -n 10 file.txt
# 多个文件
head -n 5 file1.txt file2.txt

tail:取文件末尾若干行

1
2
3
4
tail -n 20 file.txt

# -f 跟踪文件新增内容,常用于看日志;Ctrl‑C退出;不要写在脚本中阻塞!
tail -n 25 -f /var/log/messages

4.7 其他小工具速览

命令 用途
od 输出原始八进制/十六进制字节,查看二进制文件内部
file 检测文件类型
strings 从二进制程序提取可打印文本字符串
dd 块拷贝;字符转换优先用iconv

示例

1
strings -a home01.jpg | head -c 256 | fmt -w 65

本章速查表格

命令 作用 示例
sort -t: -k1,1n 按指定字段排序 sort -t: -k3nr,3 /etc/passwd 按UID降序
LC_ALL=C sort 固定ASCII字节排序,脚本稳定输出 LC_ALL=C sort data.txt
sort -u 按排序键去重 sort -k2,2 -u file.txt
sort -o out.txt 安全输出覆盖文件 sort -o file.txt file.txt
sort uniq -c 排序并统计每行出现次数 tr -cs A-Za-z' ‘\n’ < test.txt | sort | uniq -c
uniq -d 只输出重复行 sort test.txt | uniq -d
fmt -w 40 文本折行,设置行宽 fmt -w 40 note.txt
wc -lwc 统计行、单词、字节 wc /etc/passwd
pr -c4 -t 多栏格式化,关闭页眉 cat words.txt | pr -c4 -t
head -n 10 取前10行 head -n 10 /etc/passwd
tail -n 20 取末尾20行 tail -n 20 /var/log/syslog
tail -f 跟踪日志增长(交互式) tail -f /var/log/messages

本章小结

  1. sort是本章重点;locale环境变量是高频坑,脚本建议固定LC_ALL=C sort
  2. uniq只处理相邻重复,必须搭配sort;区分sort‑u(按键去重)和sort|uniq(整行去重)。
  3. fmt非POSIX,可移植脚本尽量少用。
  4. wc统计行、词、字节字符。
  5. pr用于打印前分页、多栏排版;headtail截取首尾。
  6. 工具设计哲学:输入输出为标准流,管道串联完成复杂文本处理。