这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。
日志、配置、CSV、JSON、命令输出都是文本。Linux 提供了一组小而强的工具:grep 查、sed 改、awk 切、sort 排、uniq 统计、cut 取列。组合它们,可以在几分钟内完成大量定位工作。
6.1 查看与统计
cat app.log
less app.log
head -n 100 app.log
tail -n 100 app.log
tail -F app.log
wc -l app.log
wc -c app.log
less 常用操作:
| 按键 | 作用 |
|---|---|
/word |
向下搜索 |
?word |
向上搜索 |
n |
下一个 |
N |
上一个 |
G |
到文件末尾 |
g |
到文件开头 |
q |
退出 |
编码问题:
file app.log
iconv -f GBK -t UTF-8 old.log > new.log
6.2 grep 详解
基础:
grep ERROR app.log
grep -i error app.log
grep -n ERROR app.log
grep -v DEBUG app.log
grep -E 'ERROR|WARN' app.log
grep -F '10.20.30.40' access.log
grep -c ERROR app.log
grep -r "listen 80" /etc/nginx
上下文:
grep -A 5 ERROR app.log
grep -B 5 ERROR app.log
grep -C 10 ERROR app.log
文件过滤:
grep -r --include='*.log' ERROR /var/log
grep -r --exclude='*.gz' ERROR /var/log
正则示例:
grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}' app.log
grep -E 'status=[45][0-9]{2}' access.log
grep -E '\btimeout\b' app.log
grep 按行匹配,不适合解析复杂嵌套 JSON。结构化数据优先使用 jq。
6.3 cut 与 awk
cut 适合简单分隔符:
cut -d: -f1 /etc/passwd
cut -d, -f1,3 users.csv
cut -c1-20 app.log
awk 按字段处理:
awk '{print $1}' access.log
awk -F: '{print $1, $7}' /etc/passwd
awk -F, '{print $1, $3}' users.csv
awk 'END {print NR}' app.log
条件:
awk '$9 >= 500 {print $1, $7, $9}' access.log
awk '/ERROR/ {print $1, $5}' app.log
awk -F, '$3 > 100 {sum += $3} END {print sum}' orders.csv
格式化:
awk '{printf "%-20s %10s\n", $1, $7}' access.log
内置变量:
| 变量 | 含义 |
|---|---|
NR |
当前行号 |
NF |
当前字段数 |
FS |
输入分隔符 |
OFS |
输出分隔符 |
FILENAME |
当前文件名 |
示例:
awk -F'|' 'BEGIN{OFS=","} {print $1, $3, $5}' events.log
6.4 sed 详解
替换:
sed 's/ERROR/error/' app.log
sed 's/ERROR/error/g' app.log
sed 's/port=8080/port=9090/' app.conf
sed -i 's/port=8080/port=9090/' app.conf
删除:
sed '/^#/d' app.conf
sed '/^$/d' app.conf
sed '1d' users.csv
sed '$d' users.csv
显示:
sed -n '10,20p' app.log
sed -n '/ERROR/p' app.log
插入:
sed '/^\[server\]/a listen=9090' app.ini
sed '1i # generated by ops' app.conf
安全修改:
cp app.conf app.conf.bak
sed -i 's/debug=true/debug=false/' app.conf
diff -u app.conf.bak app.conf
GNU sed 与其他平台的参数细节可能不同。跨平台脚本应先测试。
6.5 sort 与 uniq
排序:
sort app.log
sort -r app.log
sort -n sizes.txt
sort -h sizes.txt
sort -t, -k2 users.csv
sort -u ips.txt
统计:
sort ips.txt | uniq -c
sort ips.txt | uniq -c | sort -nr
sort ips.txt | uniq -d
sort ips.txt | uniq -u
经典统计:访问次数前 10 的 IP:
awk '{print $1}' access.log |
sort |
uniq -c |
sort -nr |
head -10
uniq 只合并相邻重复行,所以通常要先 sort。
6.6 join 与 diff
join 合并两个已排序文件:
join -t, -1 1 -2 1 users.csv orders.csv
diff 比较差异:
diff -u old.conf new.conf
diff -rq /opt/app/releases/v1 /opt/app/releases/v2
配置发布前建议保存差异:
diff -u /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf
6.7 正则表达式
常用元字符:
| 符号 | 含义 |
|---|---|
. |
任意单个字符 |
* |
前一个元素零次或多次 |
+ |
一次或多次,扩展正则 |
? |
零次或一次,扩展正则 |
^ |
行首 |
$ |
行尾 |
[abc] |
字符集合 |
[^abc] |
排除字符 |
\b |
单词边界 |
() |
分组 |
| |
或 |
示例:
grep -E '^2026-08-25.*(ERROR|WARN)' app.log
grep -E 'user_id=[0-9]+' app.log
sed -E 's/([0-9]{3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/<ip>/g' access.log
日志脱敏要在采集或展示层统一实现,不能只依赖临时命令。
6.8 jq 处理 JSON
安装:
sudo apt install jq
sudo dnf install jq
格式化:
echo '{"id":1,"status":"PAID"}' | jq .
jq . events.json
取字段:
jq '.status' event.json
jq '.user.id' event.json
jq '.items[0].sku' event.json
数组:
curl -s http://localhost:8080/api/users | jq '.[] | {id, name}'
jq '[.[] | select(.status == "PAID")]' orders.json
jq 'length' orders.json
统计:
jq -r '.[] | .city' orders.json | sort | uniq -c
jq -r '.[] | [.id, .amount] | @tsv' orders.json
6.9 xargs 与并行
xargs 把输入变成命令参数:
cat hosts.txt | xargs -n1 ping -c1
find /var/log -name '*.gz' | xargs ls -lh
find /tmp -name '*.tmp' | xargs rm
处理空格和特殊字符:
find /opt/app -type f -name '*.log' -print0 | xargs -0 grep ERROR
并行:
cat hosts.txt | xargs -P 10 -n1 ping -c1
删除类命令先预览:
find /tmp -name '*.tmp' -print
find /tmp -name '*.tmp' -print0 | xargs -0 rm
6.10 生产日志案例
案例一:统计错误分布
grep -E 'ERROR|WARN' app.log |
awk -F'|' '{print $2}' |
sort |
uniq -c |
sort -nr |
head -20
案例二:定位某用户请求
grep 'userId=10001' app.log
grep 'trace_id=7f3a' app.log
案例三:压缩日志查找
zgrep ERROR app.log.gz
zcat app.log.gz | grep ERROR
zless app.log.gz
案例四:统计 HTTP 状态
awk '{print $9}' access.log |
sort |
uniq -c |
sort -k2n
Nginx 日志格式不同时,字段位置可能不同,应先看日志格式定义。
6.11 性能与边界
大文件处理:
- 先缩小时间范围;
- 再按关键字过滤;
- 避免无意义的全量
cat; - 压缩日志用
zgrep; - 超大文本考虑日志平台或数据库。
示例:
grep '^2026-08-25 10:' app.log | grep ERROR
复杂需求不要无限堆管道。当脚本超过一定复杂度,改用 Python、Go 或日志平台更清晰。
本章小结
文本处理遵循“过滤、切分、排序、统计、输出”的思路。grep 找行,awk 处理字段,sed 做流编辑,sort 和 uniq 完成统计,jq 处理 JSON,xargs 把文本转成参数。临时命令高效,但长期方案应沉淀到脚本、监控和日志平台。
思考题
- 为什么
uniq之前通常要sort? sed -i修改文件前应做什么?- 如何安全处理包含空格的文件名?
grep和jq各适合什么数据格式?- 设计一条管道统计 Nginx 日志中 5xx 响应最多的 URL。