Linux 文本处理 — 三剑客

如果说前面几篇是"会用 Linux",这一篇就是"爱上 Linux"。grep、sed、awk 被称为文本三剑客,加上 find,组合起来能完成 Python 几十行代码才能做的事。日志分析、批量改名、数据提取都离不开它们。

1. grep:按行搜索

grep 是 "global regex print" 的缩写(源自古老 Unix 的 g/re/p 命令)。作用就一个:在文件或输入里找出含某个模式的行。它是排查日志最常用的工具。

# grep:global regex print,按行搜索(全局正则匹配打印)

# 基本用法:grep "关键字" 文件
grep "error" app.log              # 找含 error 的行
grep "ERROR" app.log              # 大小写敏感(ERROR 和 error 不同)

# 常用选项
grep -i "error" app.log           # -i:ignore case,不分大小写
grep -n "TODO" *.py               # -n:显示行号
grep -r "TODO" ./src              # -r:recursive,递归搜子目录
grep -v "debug" app.log           # -v:invert,反向(不含 debug 的行)
grep -c "error" app.log           # -c:count,只输出匹配行数
grep -l "error" *.log             # -l:只输出含匹配的文件名
grep -w "error" app.log           # -w:word,整词匹配(不匹配 errors)
grep -A 2 "error" app.log         # -A 2:匹配行 + 后 2 行(After)
grep -B 2 "error" app.log         # -B 2:匹配行 + 前 2 行(Before)
grep -C 2 "error" app.log         # -C 2:前后各 2 行(Context)

# 配合管道
ps aux | grep nginx               # 在进程列表里找 nginx
dmesg | grep -i usb               # 在内核日志里找 USB 信息

几个高频组合:grep -rn 在代码库里找关键字、grep -v 排除无关行、grep -i 忽略大小写。ps aux | grep nginx(找进程)、history | grep ssh(找历史命令)是日常必备。

2. sed:流编辑器

sed 是 "stream editor" 的缩写,最常用于批量替换。它的语法乍看奇怪,但用熟了几秒钟就能搞定一批文件的改名、改字段。

# sed:stream editor,流编辑器(常用于批量替换)

# 替换(substitute):s/旧/新/
sed 's/foo/bar/' file.txt         # 每行第一个 foo 换成 bar
sed 's/foo/bar/g' file.txt        # g:global,所有 foo 都换
sed 's/foo/bar/gi' file.txt       # i:不分大小写
sed 's/foo/bar/2' file.txt        # 只换每行第 2 个

# 直接修改原文件(谨慎!)
sed -i 's/foo/bar/g' file.txt     # -i:in-place,直接改原文件
sed -i.bak 's/foo/bar/g' file.txt # -i.bak:改之前备份成 file.txt.bak

# 定址:指定哪些行要处理
sed '3d' file.txt                 # 删除第 3 行
sed '2,5d' file.txt               # 删除第 2 到 5 行
sed '/^#/d' file.txt              # 删除以 # 开头的行(去掉注释)
sed '5s/foo/bar/' file.txt        # 只在第 5 行替换

# 多条命令用 -e
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt

# 插入和追加
sed '2i 新行内容' file.txt        # 第 2 行前插入
sed '2a 新行内容' file.txt        # 第 2 行后追加

最常用的就是 sed -i 's/旧/新/g':-i 直接改原文件,g 全局替换。-i 前一定先备份或用 -i.bak 让 sed 自动备份,因为它没有"撤销"。

3. awk:按列处理

awk(三位作者 Aho、Weinberger、Kernighan 姓氏首字母)是一个完整的文本处理语言,最擅长按列处理表格数据。psdfls -l 输出的列式数据,awk 一行就能提取你想要的列。

# awk:按列处理(适合表格、CSV、ps 输出)
# 基本格式:awk '条件 {动作}' 文件
#   默认按空格/Tab 分列,$0=整行 $1=第一列 $2=第二列...

# 打印特定列
ps aux | awk '{print $1, $11}'    # 打印第 1 列(用户)和第 11 列(命令)
df -h | awk '{print $1, $5}'      # 打印文件系统和占用率
awk -F',' '{print $2}' data.csv   # -F',' 指定逗号为分隔符(CSV)

# 条件过滤(NR=行号,NF=列数)
awk 'NR==1' file.txt              # 只打印第 1 行
awk 'NR>1' file.txt               # 跳过表头(从第 2 行开始)
awk 'NR>1 {print $5}' file.txt    # 跳过表头打印第 5 列
awk 'NF>3' file.txt               # 只打印列数大于 3 的行
awk '$3 > 100' scores.txt         # 第 3 列大于 100 的行
awk '$1 == "ERROR" {print $0}' log # 第 1 列等于 ERROR 的整行

# 算术:统计某列的总和
awk '{sum += $2} END {print sum}' sales.txt
#   统计第 2 列总和,END 在所有行处理完后执行

# 计算平均值
awk '{sum+=$2; n++} END {print sum/n}' scores.txt

关键概念:$0 整行、$1 第一列、$2 第二列;NR 当前行号、NF 当前行列数;-F 指定分隔符(默认空格)。awk '{sum+=$2} END {print sum}' 统计某列总和,在分析销售、监控数据时极其方便。

4. find:查找文件

find功能最强的文件查找工具。和按名字模糊匹配的 locate 不同,find 可以按名字、类型、大小、时间、权限等几乎所有属性查找,还能对结果执行命令。

# find:在目录树里查找文件(功能最强)

# 按文件名
find . -name "*.py"               # 当前目录递归找所有 .py 文件
find . -name "*.py" -type f       # -type f 只找普通文件
find /var/log -name "*.log"
find . -iname "*.JPG"             # -iname:不分大小写

# 按类型
find . -type d -name "node_modules"   # 只找目录(d)
find . -type l                     # 只找软链接(l)

# 按时间(单位:天)
find . -mtime -7                  # 7 天内修改过的(- 表示内)
find . -mtime +30                 # 30 天前修改过的(+ 表示前)
find . -mmin -60                  # 60 分钟内修改过的

# 按大小
find . -size +100M                # 大于 100MB 的文件
find . -size -1k                  # 小于 1KB 的文件

# 找到后执行动作(-exec)
find . -name "*.log" -exec rm {} \;          # 删掉找到的日志
find . -name "*.bak" -exec mv {} /tmp/ \;    # 移到 /tmp
find . -name "*.js" -exec wc -l {} \;        # 统计每个文件行数
find . -name "*.py" -exec grep "TODO" {} \;  # 在找到的文件里搜 TODO

# 配合 xargs 更高效(下一篇管道会讲)
find . -name "*.log" | xargs grep "error"

find ... -exec 是 find 的杀手锏,但语法有个怪癖:命令必须以 \; 结尾(转义分号),{} 代表找到的每个文件。批量清理日志、批量改权限都用得上。

5. 其他高频文本工具

三剑客之外,还有几个小工具也极常用,组合起来威力倍增:

# 其他高频文本工具

# wc:word count,统计
wc -l file.txt                    # 行数
wc -w file.txt                    # 单词数
wc -c file.txt                    # 字节数

# sort:排序
sort file.txt                     # 默认按字典序
sort -n nums.txt                  # 按数字排序
sort -rn nums.txt                 # 反向数字排序(从大到小)
sort -u names.txt                 # 排序并去重
sort -t',' -k2 sales.csv          # 按第 2 列排序(-t 分隔符)

# uniq:去重(只去相邻的重复行,所以先 sort)
sort names.txt | uniq             # 排序后去重
sort names.txt | uniq -c          # 去重并统计每条出现次数
sort names.txt | uniq -c | sort -rn  # 出现次数从多到少(超常用)

# cut:按列切
cut -d',' -f1,3 data.csv          # -d 分隔符,-f 取第 1、3 列
cut -c1-10 file.txt               # 取每行的第 1-10 个字符

# tr:translate,字符转换
echo "Hello" | tr 'a-z' 'A-Z'     # 小写转大写
echo "a,b,c" | tr ',' '\n'        # 逗号换行
cat file.txt | tr -d '\r'         # 删除所有 \r(Windows 换行转 Unix)

6. 经典组合:统计访问日志里出现最多的 IP

这是面试和实战都会问的经典场景,完美展示了 Unix "小工具组合"的哲学:

整套链路就一行管道命令,几十秒出结果。这就是命令行的魅力。

7. 正则表达式速成

grep、sed、awk 都依赖正则表达式,掌握几个基础元字符就够日常用:

grep -E(或别名 egrep)启用扩展正则,元字符更省事。

小结

这一篇你认识了 Linux 文本处理的四大金刚:grep 找行、sed 改字符、awk 处理列、find 找文件,以及 sortuniqwccuttr 等辅助。下一篇讲进程管理——看看程序是怎么跑起来的、怎么杀掉卡住的进程。

← 上一篇 Linux 权限管理

下一篇 Linux 进程管理

✈️💬