Shell Daily 2026-01-06: 精准提取 (Grep Only)
在日志分析中,我们经常面临这样的需求:只想把日志里的 IP 地址、订单号或 URL 单独抠出来。
为了达到这个目的,很多人的肌肉记忆是“组合拳”:先用 grep 过滤行,再用 awk 切分列,或者用 sed 做正则替换。比如为了拿一个 IP,可能写出 awk '{print $3}' 这种依赖列位置的代码,一旦日志格式变动,脚本立马失效。
其实,grep 早就具备了将它变成提取工具的能力,你只需要一个参数:-o (Only matching)。
怎么用
通常 grep 会输出包含匹配内容的整行,而加上 -o 后,它只会输出匹配到的部分。每一处匹配都会单独占一行。
- 语法:
grep -o "正则表达式" file - 兼容性:Linux (GNU grep) 和 macOS (BSD grep) 均支持。
适用场景
- 数据清洗:从杂乱的文本中提取结构化数据(如邮箱、链接)。
- 统计分布:配合
sort | uniq -c,统计某个特定模式(如错误码、API 接口)出现的频率。
示例 1:提取所有的 IP 地址
假设你有个 access.log,你想把里面所有的客户端 IP 拿出来,不管它出现在日志的第几列:
# -E 表示使用扩展正则 (Extended Regex)
# -o 表示只输出匹配到的 IP 字符串
grep -o -E "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log# 输出结果不再是整行日志,而是纯净的 IP 列表:
# 192.168.1.1
# 10.0.0.5
# ...
示例 2:高频词统计 (Top K)
这是一个价值极高的组合技。假设你想知道今天的 Nginx 日志里,哪个 URL 报错(404)最多。
如果用 awk,你得数 URL 在第几列。用 grep -o,直接用正则匹配 URL 路径即可:
# 1. 先过滤出 404 的行
# 2. 用 grep -o 提取出请求路径 (比如 /api/v1/user/...)
# 3. 排序并统计频率
grep " 404 " access.log \| grep -o -E "/api/[a-zA-Z0-9/_]+" \| sort | uniq -c | sort -nr | head -5# 输出:
# 150 /api/v1/old_endpoint
# 89 /api/v2/glitchy_image.png
(注:把 grep 从“搜索行”变为“提取器”,能让你彻底摆脱对列号的依赖,写出更健壮的数据处理管道。)