文本三剑客与重定向管道
校招考察频度:★ 高频(面试手撕命令行·线上排查杀手锏) 一句话速记:
grep找行(抓异常堆栈),awk截列(报表统计 IP PV),sed批量改(配置无交互替换);管道|串联一切;uniq -c之前必须先sort;2>&1是将标准错误挂到标准输出之后。
在 Linux 运维排障中,海量日志几乎全部以文本形式流转。熟练使用“管道符、重定向”与“文本三剑客(grep、awk、sed)”,能够在短短数秒内从几千万行日志中准确定位生产事故源头。
一、输入输出重定向与管道机制
1. 三大标准文件描述符
在 Linux 进程启动时,默认会自动打开三个文件描述符(File Descriptor,简称 FD):
| 文件描述符(FD) | 名称 | 设备/默认指向 | 符号缩写 |
|---|---|---|---|
0 | 标准输入(Standard Input / stdin) | 键盘终端 | < |
1 | 标准输出(Standard Output / stdout) | 屏幕显示器终端 | > |
2 | 标准错误(Standard Error / stderr) | 屏幕显示器终端 | 2> |
2. 重定向操作符
>:覆盖重定向。将左侧输出写入目标文件(若文件已存在则先清空原内容);>>:追加重定向。将左侧输出追加写入目标文件末尾;<:输入重定向。让命令从指定文件读取内容而非键盘;|:管道符。将前一个命令的标准输出(stdout)直接对接为后一个命令的标准输入(stdin)。
3. 面试经典深水题:> /dev/null 2>&1 原理解析
启动后台脚本或定时任务(crontab)时,经常见到这句经典指令:
nohup python3 app.py > /dev/null 2>&1 &> /dev/null 2>&1 重定向数据流向
逐段拆解:
> /dev/null:完整的写法是1 > /dev/null,表示将**标准输出(stdout)**导向 Linux 的黑洞设备/dev/null(所有写入内容直接丢弃);2>&1:2>代表重定向标准错误;&1代表引用文件描述符 1 目前指向的目标;- 整体含义:让标准错误(stderr)也输出到标准输出所在的目标(即
/dev/null)。
- 为什么不能写成
2>&1 > /dev/null?(高频踩坑)- Shell 的重定向解析是从左向右顺序执行的;
- 如果写成
2>&1 > /dev/null:执行2>&1时,FD 1 仍指向屏幕,此时 FD 2 被绑定到了屏幕;接着执行> /dev/null,仅将 FD 1 导向了黑洞,导致错误日志依然会疯狂打印在屏幕上!
二、文本三剑客之一:grep(行过滤利器)
grep 用于在文件或标准输入中基于正则表达式搜索包含匹配模式的“行”。
1. 生产高频常用参数
| 参数 | 说明 | 生产实战场景 |
|---|---|---|
-i | 忽略大小写(ignore-case) | grep -i "error" app.log |
-v | 反向匹配(invert-match),输出不匹配的行 | ps -ef | grep java | grep -v grep(过滤掉自身的 grep 进程) |
-n | 显示匹配行在源文件中的行号 | 快速定位在代码文件第几行 |
-c | 仅统计匹配到的总行数(count) | 快速查看今日发生了多少次告警 |
-r 或 -R | 递归搜索目录下所有子目录及文件 | grep -rn "API_KEY" /data/config/ |
-E | 支持扩展正则表达式(等价于 egrep) | 支持 |、+、? 等高级正则 |
2. 线上日志排查核心杀手锏:上下文行(-C、-A、-B)
线上微服务抛出异常堆栈时,报错行通常只有一句话(如 NullPointerException),具体调用栈在紧随其后的几行。如果只执行普通 grep,只能拿到一行根本无法定位:
# 1. 抓取关键字及其前后各 5 行(Context,推荐)
grep -C 5 "NullPointerException" app.log
# 2. 抓取关键字及其后 10 行(After,看紧随其后的堆栈)
grep -A 10 "OutOfMemoryError" app.log
# 3. 抓取关键字及其前 5 行(Before,看触发报错前的请求入参日志)
grep -B 5 "TimeoutException" app.log3. 多条件逻辑组合
# 逻辑与(AND):包含 ERROR 且包含 UserLogin
grep "ERROR" app.log | grep "UserLogin"
# 逻辑或(OR):包含 ERROR 或者包含 WARN
grep -E "ERROR|WARN" app.log三、文本三剑客之二:awk(列提取与报表统计)
如果说 grep 擅长按“行”过滤,那么 awk 则是按“列(字段)”切分提取与统计的王者。它本身是一门图灵完备的轻量级文本编程语言。
1. 核心语法模型与内置变量
awk 'BEGIN{初始逻辑} /匹配条件/ {每行执行动作} END{收尾汇总动作}' 文件名$0:表示当前读入的整行完整文本;$1, $2, ... $n:分别表示被切分后的第 1 列、第 2 列…第 n 列;$NF:最后一列(倒数第二列写作$(NF-1));NR:当前记录的行号(Number of Record);NF:当前行所包含的总字段数(Number of Fields);-F:指定列分隔符。默认以空格或连续制表符(Tab)切分。
2. 生产实用高频单行脚本
# 1. 提取指定列(如打印第一列 IP 和第七列请求路径)
awk '{print $1, $7}' access.log
# 2. 指定冒号为分隔符提取(如查询系统所有用户名与对应 Shell)
awk -F ':' '{print $1, $NF}' /etc/passwd
# 3. 条件判断与过滤:仅打印 HTTP 状态码为 500 的请求(假设第 9 列是状态码)
awk '$9 == 500 {print $1, $7, $9}' access.log
# 4. 数值累加:计算访问日志中所有响应数据大小的总和(假设第 10 列是 response_size 字节数)
awk '{sum += $10} END {print "Total Response Size (MB):", sum/1024/1024}' access.log四、文本三剑客之三:sed(流编辑器与批量修改)
sed(Stream Editor)是一个非交互式的流编辑器。它逐行处理输入流并进行编辑,最常用于批量文本替换、删行或脚本化改配置。
1. 字符串替换语法
# 1. 预览替换(不改原文件,输出到屏幕观察):s 代表 substitute,g 代表 global 全局替换
sed 's/localhost:3306/192.168.1.100:3306/g' config.env
# 2. 生产直接修改文件(-i: in-place 原地修改)
sed -i 's/DEBUG = True/DEBUG = False/g' settings.py
# 3. 安全原地修改并自动保留备份文件(生成 settings.py.bak)
sed -i.bak 's/DEBUG = True/DEBUG = False/g' settings.py2. 行删除与按行操作
# 删除第 1 到 10 行
sed '1,10d' file.txt
# 删除所有包含 "DEBUG" 关键字的行
sed -i '/DEBUG/d' app.log五、黄金辅助搭档:sort、uniq、wc
在日志统计场景中,awk 提取出数据后,必须配合 sort 与 uniq 才能完成统计分析。
1. 命令核心参数
| 命令 | 关键参数 | 说明 |
|---|---|---|
sort | -n | 按数值大小排序(默认是按 ASCII 字符字典序排序,若不加 -n,10 会排在 2 前面!) |
-r | 逆序排列(从大到小降序) | |
-k 2 | 指定以第 2 列为基准进行排序 | |
uniq | -c | 在每行前显示该行连续重复出现的计数次数 |
wc | -l | 统计文本的总行数(line count) |
六、经典面试压轴题实战:Top 10 IP 统计流水线
题目:如何统计 Nginx 访问日志中访问量最高的前 10 个 IP?
这是大厂校招与社招运维开发中出现率最高的“必答题”。
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -n 10经典 Top 10 IP 统计管道数据流向与变换过程
执行链路分解:
awk '{print $1}' access.log:抽取 access.log 每行首列的客户端 IP;sort:将所有 IP 进行字典序排序,使相同的 IP 聚集在一起;uniq -c:统计每个 IP 连续出现的频次,输出形如1250 192.168.1.1;sort -nr:-n按照第一列频次数值比较,-r按访问量从高到低降序;head -n 10:截取前 10 行,得到 Top 10 访问 IP 排行榜。
七、高频面试追问
-
awk和sed的应用场景有什么本质差异?awk更擅长对列(字段)进行提取、条件判断和数值计算统计,常用于报表生成和日志行为分析;sed更擅长按行做非交互式的正则查找、字符串替换与删减,常用于自动化运维脚本中批量修改配置文件。
-
什么是重定向中的覆盖
>与追加>>?如果只想丢弃日志不存盘该怎么做?>会截断已有目标文件并从头覆盖;>>会保持原文件内容并在其尾部追加新日志;- 丢弃日志可以直接重定向到 Linux 特殊设备
/dev/null,它是系统的“黑洞”,任何写入它的内容都会被系统丢弃且不占用磁盘空间。
-
grep怎样递归搜索目录下所有文件?如果只想看哪些文件包含关键词而不看具体内容怎么办?- 递归搜索使用
grep -r "pattern" /path; - 若只想打印包含该模式的文件名列表,可以加上
-l(list files)参数:grep -rl "ERROR" /data/logs/。
- 递归搜索使用