Skip to content

文本三剑客与重定向管道

grep 模式过滤、awk 列提取与统计、sed 流替换、管道符与标准输入输出重定向。

Updated View as Markdown
For humans

文本三剑客与重定向管道

校招考察频度:★ 高频(面试手撕命令行·线上排查杀手锏) 一句话速记: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 重定向数据流向

逐段拆解:

  1. > /dev/null:完整的写法是 1 > /dev/null,表示将**标准输出(stdout)**导向 Linux 的黑洞设备 /dev/null(所有写入内容直接丢弃);
  2. 2>&1:
    • 2> 代表重定向标准错误;
    • &1 代表引用文件描述符 1 目前指向的目标;
    • 整体含义:让标准错误(stderr)也输出到标准输出所在的目标(即 /dev/null)。
  3. 为什么不能写成 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.log

3. 多条件逻辑组合

# 逻辑与(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.py

2. 行删除与按行操作

# 删除第 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 统计管道数据流向与变换过程

执行链路分解:

  1. awk '{print $1}' access.log:抽取 access.log 每行首列的客户端 IP;
  2. sort:将所有 IP 进行字典序排序,使相同的 IP 聚集在一起;
  3. uniq -c:统计每个 IP 连续出现的频次,输出形如 1250 192.168.1.1;
  4. sort -nr:-n 按照第一列频次数值比较,-r 按访问量从高到低降序;
  5. head -n 10:截取前 10 行,得到 Top 10 访问 IP 排行榜。

七、高频面试追问

  1. awk 和 sed 的应用场景有什么本质差异?

    • awk 更擅长对列(字段)进行提取、条件判断和数值计算统计,常用于报表生成和日志行为分析;
    • sed 更擅长按行做非交互式的正则查找、字符串替换与删减,常用于自动化运维脚本中批量修改配置文件。
  2. 什么是重定向中的覆盖 > 与追加 >>?如果只想丢弃日志不存盘该怎么做?

    • > 会截断已有目标文件并从头覆盖;>> 会保持原文件内容并在其尾部追加新日志;
    • 丢弃日志可以直接重定向到 Linux 特殊设备 /dev/null,它是系统的“黑洞”,任何写入它的内容都会被系统丢弃且不占用磁盘空间。
  3. grep 怎样递归搜索目录下所有文件?如果只想看哪些文件包含关键词而不看具体内容怎么办?

    • 递归搜索使用 grep -r "pattern" /path;
    • 若只想打印包含该模式的文件名列表,可以加上 -l(list files)参数:grep -rl "ERROR" /data/logs/。
Navigation

Type to search…

↑↓ navigate↵ selectEsc close