当前位置:首页>Linux>Linux三剑客(grep/sed/awk)实战技巧,效率翻倍就靠它们

Linux三剑客(grep/sed/awk)实战技巧,效率翻倍就靠它们

  • 2026-06-30 14:07:35
Linux三剑客(grep/sed/awk)实战技巧,效率翻倍就靠它们

一、问题场景(为什么需要关注这个问题)

1.1 运维工程师的基本功

在十余年的一线运维工作中,笔者无数次面临这样的场景:生产环境的日志文件超过10GB,需要在5分钟内定位某个异常时间点的错误信息;或者需要在数百台服务器上批量修改某个配置参数;又或者要从海量监控数据中提取关键指标生成日报。这些任务在图形化工具中几乎无法完成,或者需要耗费数小时甚至数天的时间。

然而,使用grep、sed、awk这三个文本处理工具,同样的任务往往可以在数秒到数分钟内完成。这不是夸张,而是无数次实战验证的事实。

为什么面试必问底层能力

在技术面试中,grep/sed/awk的使用能力是区分初级工程师和资深工程师的重要分水岭。面试官考察的不仅是命令记忆,更是候选人对文本处理的理解深度、正则表达式的掌握程度、以及解决实际问题的思路。那些能够脱口而出"grep -P用Perl正则"、"sed的模式空间和保持空间"、"awk的关联数组"等概念的候选人,往往在实际工作中也表现出更强的技术能力。

GUI工具的局限

不可忽视的是,图形化工具在某些场景下确实有其价值——可视化程度高、学习曲线平缓、适合初学者快速上手。然而,当面对以下场景时,GUI工具会立即暴露其根本性缺陷:

  1. 大文件处理:超过1GB的日志文件,大多数文本编辑器会直接崩溃或卡顿,而grep/sed/awk可以轻松处理数十GB的文件
  2. 批量操作:需要修改100台服务器的配置文件,GUI工具无能为力,而一行shell脚本可以完成任务
  3. 自动化场景:需要每天定时执行数据提取任务,GUI工具无法实现,而cron job配合shell脚本可以完美解决
  4. 精确匹配:需要找到所有包含特定模式的行,GUI的搜索功能远不如正则表达式强大
  5. 跨平台一致性:在Linux服务器环境中,没有GUI可用,必须依靠命令行工具

三剑客的江湖地位:40年不过时

grep最初由Ken Thompson在1974年为Unix系统编写,sed的雏形出现在1978年,awk诞生于1977年。这三款工具至今已有近50年的历史,却依然是Linux/Unix系统中最常用、最高频使用的文本处理工具。根据笔者对生产环境的统计,这三个命令在日常运维工作中出现的频率远超其他工具。

这不是因为没有更好的替代品,而是因为它们的设计哲学经过时间检验,至今仍是处理文本最优雅、最高效的方案。GNU grep 3.11、GNU sed 4.9、GNU awk (gawk) 5.3这些最新版本在保持向后兼容的同时,不断融入新特性以适应现代计算环境的需求。

效率差距的量化对比

以下是一个实际案例的对比:提取nginx访问日志中所有POST请求的来源IP,并统计访问次数前10的IP。

使用Python脚本实现,需要约30行代码,处理时间约45秒(对于1GB日志文件)。而使用awk单行命令:

awk '$6 ~ /POST/ {print $1}' access.log | sort | uniq -c | sort -rn | head -10

同样的任务,执行时间不足3秒,代码仅一行。

1.2 典型使用场景

日志分析:找到error、分析调用链、统计请求量

日志分析是运维工程师最频繁的工作之一。三剑客在日志分析场景中展现出了极大的灵活性:

# 提取所有ERROR级别的日志,并显示前后5行上下文grep -C 5 "ERROR" /var/log/application.log# 统计每种错误码的出现次数grep -o '"status":[0-9]*' app.log | sort | uniq -c | sort -rn# 分析请求来源分布awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

配置管理:批量替换、提取配置值、校验配置

在管理大量服务器时,配置文件的一致性至关重要:

# 批量将所有服务器的某个配置项从localhost改为实际IPfind /etc -name "*.conf" -exec sed -i 's/bind-address.*=.*localhost/bind-address=0.0.0.0/g' {} \;# 从nginx配置中提取所有server_namegrep -E '^\s*server_name' /etc/nginx/nginx.conf | sed 's/.*server_name\s*//g; s/;//g'# 校验配置文件中是否存在禁止的配置项grep -E '^\s*root\s+/html' /etc/nginx/*.conf && echo"WARNING: Found potential security issue"

数据处理:日志切割、格式转换、报表生成

# 将CSV转换为带表头的格式化表格awk -F',''BEGIN {printf "%-20s %-15s %-10s\n", "Name", "Email", "Phone"}          {printf "%-20s %-15s %-10s\n", $1, $2, $3}' data.csv# 从日志中提取关键指标生成日报awk '/\[2026-04-24/ {sum[$4]++}     END {for(k in sum) printf "%s: %d requests\n", k, sum[k]}' access.log

监控告警:日志实时过滤、自动告警触发

# 实时监控错误日志,发现异常立即告警tail -f /var/log/application.log | grep --line-buffered "ERROR\|FATAL" | \whileread line; doecho"$line" | mail -s "ALERT: Error detected" admin@example.comdone# 使用watch配合三剑客实现周期性监控watch -n 60 'grep "ERROR" /var/log/app.log | wc -l'

故障排查:快速定位问题、提取关键信息

# 从堆栈日志中提取所有异常类型grep -E '^\s+at\s+[a-zA-Z0-9$.]+' java-error.log | \  awk '{print $2}' | sort | uniq -c | sort -rn# 找出响应时间超过阈值的请求awk -F'"''$NF ~ /time=[0-9]+/ {split($NF,a,"&"); for(i in a) if(a[i] ~ /^time=/) {split(a[i],t,"="); if(t[2]>5) print $0}}' access.log

1.3 工具选择的困惑

grep vs awk vs sed:各自擅长的领域

尽管三款工具都有文本处理能力,但它们各有专长:

工具
核心能力
最佳场景
grep
文本过滤与搜索
从大量内容中快速找到匹配的行
sed
文本替换与编辑
对文本进行原地修改、删除、插入操作
awk
文本分析与统计
按条件处理字段、生成报表、复杂统计

一个常见的问题是:sed能做替换,awk也能做替换,我该用哪个?答案是:如果只是简单的行内替换,用sed;如果涉及到字段分析、条件判断、统计计算,用awk。

组合使用:管道之力

Unix哲学的精髓在于"小工具、大作用"。三剑客真正强大的地方在于它们可以通过管道组合使用,发挥出远超单一工具的能力:

# 从日志中提取信息、过滤、统计、排序grep "2026-04-24 14:" app.log | \  awk '{print $5, $7}' | \  sort | uniq -c | sort -rn

这个管道的含义是:从app.log中提取14点至15点的日志,提取第5和第7字段,统计每种组合的出现次数,按出现次数降序排列。

正则表达式:基础与进阶

三剑客的能力很大程度上依赖于正则表达式。grep支持BRE(基本正则)和ERE(扩展正则),sed在使用-e或-r参数时支持ERE,awk原生支持ERE。GNU工具集还通过-P参数支持PCRE(Perl兼容正则表达式)。

关于正则表达式,需要特别强调的是:

  1. 默认情况下,三剑客使用 BRE/ERE,不支持 \d\w 等 Perl 风格字符类简写
  2. GNU grep 的 -P 参数启用 PCRE,gawk 的 -P 参数启用 POSIX 标准
  3. 量词 +?{n,m} 在 BRE 中需要转义,在 ERE 中不需要

性能考量:大文件处理的技巧

处理大文件时,以下技巧可以显著提升性能:

# 使用 grep -F 进行快速字符串匹配(禁用正则)grep -F "exact_string_to_find" hugefile.log# 使用 grep -l 只列出文件名,避免读取整个文件内容grep -rl "pattern" /large/directory# 使用 sed -n 配合 p 命令只输出需要的行sed -n '1000000,1000010p' hugefile.log# 使用 awk 的 NR 范围筛选awk 'NR>=1000000 && NR<=1000010' hugefile.log

二、核心原理与关键概念拆解

2.1 grep核心原理

行匹配原则:为什么是行而不是字符

grep的设计理念基于Unix的"管道"概念:每个工具负责做好自己的本职工作,然后通过管道将结果传递给下一个工具。grep的职责是过滤——它读取每一行,测试该行是否匹配模式,然后输出匹配的行。

这意味着grep的最小处理单元是行,而不是文件中的任意位置或字符范围。理解这一点对于正确使用grep至关重要:

# grep 输出的每一行都是原始文件中完整的一行$ grep "error" /var/log/syslogApr 24 10:15:32 server01 kernel: [error] Failed to mount filesystemApr 24 10:15:33 server01 systemd[1]: error: service failed to start

输出中的每一行都是原始日志文件的完整行,grep只是决定这一行是否应该被输出。

BRE vs ERE:Basic Regular Expression vs Extended

grep支持两种正则表达式语法:

  1. BRE(Basic Regular Expression):默认模式,元字符 (){}| 需要转义才表示特殊含义
  2. ERE(Extended Regular Expression):使用 -E 参数启用,元字符不需要转义
# BRE 模式:| 需要转义$ grep "error\|warning" app.log# ERE 模式:| 不需要转义$ grep -E "error|warning" app.log# BRE 模式:+ 需要转义表示字面量,加号前加反斜杠才表示"一个或多个"$ grep "a\+b" app.log    # 匹配 "a+b" 字面量# ERE 模式:+ 不需要转义表示"一个或多个"$ grep -E "a+b" app.log  # 匹配一个或多个a followed by b

GNU grep还支持 -G 参数明确指定BRE(默认),-E 指定ERE,-F 指定固定字符串(禁用正则)。

NFA/DFA:正则引擎的工作方式

正则表达式的匹配引擎主要分为两种类型:

  1. DFA(确定有限自动机):从左到右扫描输入文本,一次性尝试所有可能的匹配,速度快但功能有限
  2. NFA(非确定有限自动机):深度优先搜索,尝试匹配表达式的每个可能性,支持更多高级特性但可能回溯

GNU grep 3.11默认使用的正则引擎会根据表达式特征自动选择最合适的策略。对于简单表达式,使用类似DFA的高效算法;对于复杂表达式(如包含捕获组、环视等),使用NFA并可能涉及回溯。

匹配优化:锚点、左对齐、避免回溯

合理的正则表达式设计可以显著提升grep性能:

# 使用锚点 ^ 锚定行首,引擎可以直接从行首开始匹配$ grep "^Error" app.log      # 只匹配行首为Error的行# 使用 \b 锚定词边界$ grep "\berror\b" app.log   # 只匹配完整的"error"词# 避免贪心匹配导致的回溯$ grep "Error.*failed" app.log   # 可能导致大量回溯$ grep "Error[^:]*failed" app.log # 使用排除字符类更高效

GNU grep特性:-P、-o、-v、-E等

GNU grep提供了一系列增强选项:

# -o: 只输出匹配的部分,而非整行echo"error123 error456" | grep -o "error[0-9]*"error123error456# -v: 反向匹配,输出不包含模式的行$ grep -v "DEBUG" app.log    # 排除所有DEBUG行# -c: 统计匹配行数$ grep -c "ERROR" app.log42# -n: 显示匹配行的行号$ grep -n "ERROR" app.log10:2026-04-24 ERROR connection failed15:2026-04-24 ERROR timeout# -P: 使用Perl正则表达式(PCRE)echo"2026-04-24" | grep -P "^\d{4}-\d{2}-\d{2}$"2026-04-24# -l: 只显示包含匹配的文件名$ grep -rl "ERROR" /var/log/# -L: 只显示不包含匹配的文件名$ grep -L "ERROR" /var/log/# -h: 多个文件时不显示文件名$ grep -h "ERROR" file1.log file2.log# --include/--exclude: 文件名过滤$ grep -r "ERROR" /var/log --include="*.log" --exclude="debug.log"

2.2 sed核心原理

流编辑器:读取、执行、输出

sed的名称来自"stream editor"(流编辑器)。它的工作原理是:读取一行到模式空间,执行编辑命令,输出该行,然后读取下一行。这个"读取-执行-输出"的循环持续到文件末尾。

# sed 的基本工作流程echo"hello world" | sed 's/hello/hi/'hi world

sed默认会将处理后的内容输出到标准输出,不会修改原文件(除非使用 -i 参数)。

模式空间(Pattern Space):工作区

模式空间是sed用于存储当前处理行的临时缓冲区。每次读取新行时,模式空间会被清空并填充新内容。

# 演示模式空间echo -e "line1\nline2\nline3" | sed 'p'line1line1line2line2line3line3

p 命令打印模式空间的内容,所以每行被打印了两次(一次是sed默认输出,一次是p命令)。

保持空间(Hold Space):临时存储

保持空间是另一个缓冲区,用于在处理过程中临时存储数据。它不自动填充,需要显式命令操作。

# 保持空间操作示例:逆序输出行echo -e "line1\nline2\nline3" | sed -n '1!G;h;$p'line3line2line1

常用保持空间命令:

  • h/H:复制/追加模式空间到保持空间
  • g/G:复制/追加保持空间到模式空间
  • x:交换模式空间和保持空间

编辑命令:s、d、p、i、a、c、y

sed的核心编辑命令:

# s: 替换(substitute)echo"old old old" | sed 's/old/new/'new old old                    # 默认只替换第一个echo"old old old" | sed 's/old/new/g'new new new                    # /g 替换所有# d: 删除(delete)echo -e "line1\nline2\nline3" | sed '2d'line1line3# p: 打印(print)echo -e "line1\nline2\nline3" | sed -n '2p'line2# i: 在行前插入(insert)echo"line2" | sed '1i\line1'line1line2# a: 在行后追加(append)echo"line1" | sed '1a\line2'line1line2# c: 替换整行(change)echo -e "line1\nline2\nline3" | sed '2c\changed'line1changedline3# y: 字符转换(transform)echo"abc" | sed 'y/abc/123/'123

地址寻址:行号、范围、正则匹配

sed支持多种地址形式来指定要处理的行:

# 行号寻址echo -e "line1\nline2\nline3" | sed '2s/2/TWO/'line1lineTWOline3# 范围寻址echo -e "line1\nline2\nline3\nline4" | sed '2,3p'line1line2line2line3line3line4# 正则匹配寻址echo -e "error line\nnormal line\nerror again" | sed '/error/p'error lineerror linenormal lineerror againerror again# 排除寻址:感叹号取反echo -e "line1\nline2\nline3" | sed '2!d'line2# 首行和末行特殊用法echo -e "line1\nline2\nline3" | sed '1d'line2line3echo -e "line1\nline2\nline3" | sed '$d'line1line2

2.3 awk核心原理

记录与字段:NR、FNR、NF、1...

awk的设计初衷是"字段处理器"。它将每行文本视为一条记录,将行内的各列视为字段:

# $0: 整条记录(整行)# $1, $2, ...: 第1、2、...个字段# NF: 当前记录的字段数量(Number of Fields)# NR: 当前记录的序号(Number of Records),跨文件累加# FNR: 当前文件的记录序号,文件间独立echo"John 30 Engineer" | awk '{print $1, $3}'John Engineerecho"a b c d e" | awk '{print NF}'5echo -e "file1.txt\nfile2.txt" | awk '{print NR, FNR, $0}'1 1 file1.txt2 1 file2.txt

模式匹配:正则、条件、范围

awk的条件模式非常强大:

# 正则匹配$ awk '/error/ {print $0}' app.log# 字段匹配$ awk '$3 == "ERROR" {print $1, $2}' app.log# 数值比较$ awk '$5 > 1000 {print $1, $5}' app.log# 范围模式:匹配从start到end的所有行$ awk '/START/,/END/ {print}' app.log# 复合条件$ awk '/error/ && $4 == "CRITICAL" {print $0}' app.log

内置变量:ORS、RS、FS、OFS、FPAT

awk提供了丰富的内置变量来控制输入输出格式:

变量
说明
默认值
RS
输入记录分隔符(Record Separator)
换行符\n
FS
输入字段分隔符(Field Separator)
空格
ORS
输出记录分隔符(Output Record Separator)
换行符\n
OFS
输出字段分隔符(Output Field Separator)
空格
FPAT
字段模式(Field Pattern),定义字段内容
FILENAME
当前输入文件名
ARGIND
当前处理的ARGINDX文件序号
# 使用FS指定字段分隔符echo"2026-04-24|error|server01" | awk -F'|''{print $1, $3}'2026-04-24 server01# 使用OFS指定输出分隔符echo"John 30" | awk '{print $1, $2}' OFS=','John,30# 使用RS指定输入记录分隔符(处理多行记录)echo -e "record1\nrecord2\n\nrecord3\nrecord4" | awk 'BEGIN{RS="\n\n"} {print NR, $0}'1 record1record22 record3record4# 使用FPAT定义字段模式(提取匹配特定模式的内容)echo'href="http://example.com"' | awk 'BEGIN{FPAT="[^\"]+"} {for(i=1;i<=NF;i++) print i, $i}'1 href=2 http://example.com

函数库:字符串、数值、时间

gawk内置了大量函数:

# 字符串函数$ awk 'BEGIN{s="hello world"; print length(s), substr(s,7,5), toupper(s)}'11 world HELLO WORLD$ awk 'BEGIN{s="a,b,c"; split(s,arr,","); for(i in arr) print i, arr[i]}'1 a2 b3 c# 数值函数$ awk 'BEGIN{print sqrt(16), int(3.7), rand()}'4 3 0.382283# 时间函数$ awk 'BEGIN{print strftime("%Y-%m-%d %H:%M:%S"), systime()}'2026-04-24 14:30:00 1745494200# 自定义函数$ awk 'function max(a,b) {return a>b?a:b} BEGIN{print max(10,20)}'20

关联数组:key-value的高级用法

awk的关联数组是其最强大的特性之一:

# 基本数组操作$ awk 'BEGIN{arr["key1"]=100; arr["key2"]=200; print arr["key1"]}'100# 数组遍历$ awk '{count[$1]++} END{for(ip in count) print ip, count[ip]}' access.log192.168.1.10 1523192.168.1.11 987192.168.1.12 456# 二维数组(模拟)$ awk '{matrix[$1,$2]=$3} END{for(k in matrix) print k, matrix[k]}' data.txt# 判断键是否存在$ awk 'BEGIN{arr["a"]=1; if("a" in arr) print "exists"; if(!( "b" in arr)) print "not exists"}'existsnot exists# 删除数组元素$ awk 'BEGIN{arr["a"]=1; arr["b"]=2; delete arr["a"]; for(k in arr) print k}'b# 使用split创建数组$ awk 'BEGIN{n=split("red,green,blue",colors,","); for(i=1;i<=n;i++) print i, colors[i]}'1 red2 green3 blue

2026年扩展:gawk新特性

GNU awk 5.3版本引入了一些值得关注的新特性:

  1. 更好的Unicode支持:完整支持UTF-8编码的字符处理
  2. 扩展的正则表达式特性:支持更多PCRE特性
  3. 性能优化:大规模数据处理性能提升约15-20%
  4. 新增数组函数:如 asort() 的变体支持自定义排序
# 检查gawk版本$ gawk --versionGNU Awk 5.3.0, API: 3.2 (GNU MPFR 4.2.1, GNU MP 6.3.0)# 使用 --posix 模式启用严格POSIX兼容$ gawk --posix 'BEGIN{print length("中文")}'# 输出 2

2.4 正则表达式深度

字符类:[a-z]、[:alpha:]、\d

字符类是匹配一组字符的简洁方式:

# 简单字符类echo"a1b2c3" | grep -o "[a-z]"abc# 范围字符类echo"abc123" | grep -o "[0-9]"123# POSIX字符类echo"ABCabc" | grep -o "[[:alpha:]]"ABCabc# 常用POSIX字符类# [:alnum:] - 字母和数字# [:alpha:] - 字母# [:blank:] - 空格和制表符# [:digit:] - 数字# [:lower:] - 小写字母# [:upper:] - 大写字母# [:space:] - 空白字符# [:punct:] - 标点符号# 取反:^ 在字符类内部表示排除echo"a1b2" | grep -o "[^0-9]"ab# 组合使用echo"A1B2" | grep -o "[[:upper:]][[:digit:]]"A1B2

量词:*、+、?、{n,m}

量词用于指定匹配的次数:

# *: 零个或多个echo"a" | grep -E "ab*"aecho"abbb" | grep -E "ab*"abbb# +: 一个或多个(ERE)echo"abbb" | grep -E "ab+"abbbecho"ac" | grep -E "ab+"# ?: 零个或一个echo"ac" | grep -E "ab?"acecho"abc" | grep -E "ab?"ab# {n}: 恰好n次echo"abbc" | grep -E "ab{2}c"abbc# {n,}: 至少n次echo"abbbc" | grep -E "ab{2,}c"abbbc# {n,m}: n到m次echo"abbbc" | grep -E "ab{1,3}c"abbc

断言:^、$、\b、lookahead/behind

断言不匹配具体字符,而是匹配位置:

# ^: 行首锚点echo"hello world" | grep "^hello"hello world# $: 行尾锚点echo"hello world" | grep "world$"hello world# \b: 词边界echo"hello world hello" | grep -E "\bhello\b"hello world hello# 只匹配第一个和第三个hello(词边界)# 环视断言(lookahead/behind)# 肯定前瞻:(?=pattern) - 后面是pattern的位置# 否定前瞻:(?!pattern) - 后面不是pattern的位置# 肯定后顾:(?<=pattern) - 前面是pattern的位置# 否定后顾:(?<!pattern) - 前面不是pattern的位置# grep -P 启用PCRE支持环视echo"100 dollars 200 euros" | grep -oP '\d+(?= dollars)'100echo"100 dollars 200 euros" | grep -oP '\d+(?! dollars)'200# 提取跟在"error:"后面的内容echo"error: something went wrong" | grep -oP '(?<=error: ).*'something went wrong# 排除跟在"error:"后面的内容echo"error: handled error: unhandled" | grep -oP 'error:(?! handled).*'error: unhandled

分组与捕获:()、\1、\2

分组用于将多个元素组合为一个单元,捕获用于提取匹配的部分:

# 分组:() 将内容组合echo"abcabc" | grep -E "(abc){2}"abcabc# 捕获:() 同时捕获分组内容echo"2026-04-24" | grep -oE "([0-9]{4})-([0-9]{2})-([0-9]{2})"2026-04-24# 反向引用:\1, \2 引用捕获的内容# 将重复的词替换为单个echo"the the cat sat on the the mat" | sed 's/\b\([a-z]\+\)\b \1/\1/g'the cat sat on the mat# 交换两个单词的位置echo"John Smith" | sed 's/\([A-Za-z]\+\) \([A-Za-z]\+\)/\2 \1/'Smith John# 多级捕获echo"abc:123:def" | awk -F: '{print $1, $2, $3}'abc 123 def

常用模式:IP、Email、URL、日期

# IPv4地址echo"My IP is 192.168.1.100" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}'192.168.1.100# 更精确的IP验证echo"192.168.1.100" | grep -oE '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'192.168.1.100# Email地址echo"Contact: user@example.com for info" | grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'user@example.com# URLecho"Visit https://www.example.com:8080/path?query=1" | grep -oP 'https?://[^\s<>"]+'https://www.example.com:8080/path?query=1# 日期(ISO格式)echo"Date: 2026-04-24" | grep -oE '[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])'2026-04-24# 时间(24小时制)echo"Time: 14:30:45" | grep -oE '([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]'14:30:45

三、实战步骤与常见排障路径

3.1 grep实战技巧

基本用法

grep的最基本用法是在文件或输入中查找包含指定字符串的行:

# 在单个文件中搜索$ grep "error" /var/log/syslogApr 24 10:15:32 server01 kernel: [error] Failed to mount filesystemApr 24 10:15:45 server01 application[1234]: error: connection timeout# 递归搜索目录$ grep -r "failed" /var/log//var/log/syslog:Apr 24 10:15:32 server01 kernel: [error] Failed to mount filesystem/var/log/nginx/access.log:10.0.0.1 - - [24/Apr/2026] "GET /failed HTTP/1.1" 404# 不区分大小写搜索$ grep -i "warning" /var/log/messagesApr 24 10:15:32 server01 kernel: WARNING: memory usage highApr 24 10:15:33 server01 systemd[1]: WARNING: service may fail

高频选项

# -n: 显示行号$ grep -n "error" app.log10:2026-04-24 10:15:32 ERROR connection failed15:2026-04-24 10:15:45 ERROR timeout on request# -c: 统计匹配行数(不是匹配次数)$ grep -c "ERROR" app.log42# -A: 显示匹配行及其后n行(After)$ grep -A 5 "ERROR" app.logERROR connection failedStack trace:  at ConnectionHandler.connect (connection.js:45)  at RequestHandler.process (request.js:123)  at AsyncCallback.callback (async.js:67)# -B: 显示匹配行及其前n行(Before)$ grep -B 3 "ERROR" app.log2026-04-24 10:15:29 INFO Starting connection2026-04-24 10:15:30 DEBUG Socket opened2026-04-24 10:15:31 DEBUG Sending requestERROR connection failed# -C: 显示匹配行及其前后n行(Context)$ grep -C 3 "ERROR" app.log2026-04-24 10:15:31 DEBUG Sending request2026-04-24 10:15:32 ERROR connection failed2026-04-24 10:15:33 INFO Retrying...# -E: 使用扩展正则表达式$ grep -E "error|warn|fatal" app.logERROR connection failedWARNING high latency detectedFATAL system crash imminent# -P: 使用Perl正则表达式$ grep -P "\d{4}-\d{2}-\d{2}" app.log2026-04-24 10:15:32 ERROR connection failed2026-04-24 10:15:45 INFO system started# --color: 高亮显示匹配部分$ grep --color=auto -n "error" app.log

性能优化

# -F: 快速字符串匹配(禁用正则表达式解析)$ grep -F "exact.string.match" largefile.log# --include: 只在指定类型的文件中搜索$ grep -r "ERROR" /var/log --include="*.log"$ grep -r "ERROR" /var/log --include="*.txt" --include="*.log"# --exclude: 排除指定类型的文件$ grep -r "ERROR" /var/log --exclude="debug.log"# -l: 只显示包含匹配的文件名(遇到匹配即停止,减少I/O)$ grep -rl "ERROR" /var/log/# -L: 只显示不包含匹配的文件名$ grep -L "ERROR" /var/log/# --max-count: 达到指定匹配次数后停止读取文件$ grep -m 10 "ERROR" app.log# --binary-files: 处理二进制文件的方式$ grep --binary-files=without-match "ERROR" /bin/ls# without-match: 假定二进制文件不匹配# binary: 将其作为二进制处理# text: 将其作为文本处理(可能产生大量垃圾输出)

3.2 sed实战技巧

基础替换

sed最核心的功能是文本替换:

# 替换第一个匹配:s/old/new/echo"old text in old world" | sed 's/old/new/'new text in old world# 替换所有匹配:s/old/new/gecho"old text in old world" | sed 's/old/new/g'new text in new world# 替换第n个匹配:s/old/new/necho"a a a a a" | sed 's/a/b/2'a b a a a# 替换每行第2个及之后的匹配:s/old/new/2gecho"a a a a a" | sed 's/a/b/2g'a b b b b# 直接修改文件(危险操作):-i$ sed -i 's/old/new/g' file.txt# 带备份修改:-i.bak$ sed -i.bak 's/old/new/g' file.txt# 同时生成 file.txt.bak 备份# 在替换中使用 & 代表匹配内容echo"hello" | sed 's/hello/[&]/'[hello]# 使用捕获组echo"2026-04-24" | sed 's/\([0-9]\+\)-\([0-9]\+\)-\([0-9]\+\)/\3\/\2\/\1/'24/04/2026

高级操作

# 打印指定行:-n 配合 p$ sed -n '10,20p' file.txt# 删除匹配行:/pattern/decho -e "line1\nerror line\nline3" | sed '/error/d'line1line3# 删除不匹配行:/pattern/!decho -e "line1\nerror line\nline3" | sed '/error/!d'error line# 范围打印:/start/,/end/pecho -e "start\nline1\nline2\nend\nline3" | sed -n '/start/,/end/p'startline1line2end# 插入文本:i\echo"line2" | sed '1i\line1'line1line2# 追加文本:a\echo"line1" | sed '1a\line2'line1line2# 替换整行:c\echo -e "line1\nline2\nline3" | sed '2c\changed line'line1changed lineline3# 字符转换:y/source/dest/echo"hello" | sed 'y/aeiou/12345/'h2ll4# 保持空间操作:将所有行逆序echo -e "line1\nline2\nline3" | sed -n '1!G;h;$p'line3line2line1# 交换两行echo -e "line1\nline2" | sed '1h;2G'line2line1

多命令组合

# -e: 多个编辑命令echo"hello world" | sed -e 's/hello/hi/' -e 's/world/universe/'hi universe# ;: 在一行中组合多个命令echo"hello world" | sed 's/hello/hi/; s/world/universe/'hi universe# &: 引用整个匹配echo"123 456" | sed 's/[0-9]+/[&]/g'[123] [456]# 标签:用于条件执行和跳转echo -e "line1\nline2\nline3" | sed ':a; N; $!ba; s/\n/ /g'line1 line2 line3

3.3 awk实战技巧

基础语法

# 打印指定字段$ awk '{print $1, $3}' file.txt# 使用-F指定字段分隔符$ awk -F: '{print $1, $NF}' /etc/passwdroot /bin/bashdaemon /usr/sbin/nologin# 打印特定行$ awk 'NR==5' file.txt$ awk 'NR>=10 && NR<=20' file.txt# 统计行数$ awk 'END {print NR}' file.txt# 求和$ awk '{sum+=$1} END {print sum}' numbers.txt

条件过滤

# 字段数值比较$ awk '$3 > 100 {print $1, $3}' data.txt# 正则匹配字段$ awk '$4 ~ /ERROR/ {print $1, $2, $4}' app.log# 否定正则$ awk '$4 !~ /DEBUG/ {print $0}' app.log# 组合条件$ awk '$3 > 100 && $4 == "ERROR" {print $1, $2}' app.log# 范围模式:匹配从pattern1到pattern2的所有行$ awk '/START/,/END/ {print NR, $0}' file.txt

统计分析

# 简单计数$ awk '/ERROR/ {count++} END {print count}' app.log42# 求和$ awk '{sum+=$2} END {print sum}' data.txt# 平均值$ awk '{sum+=$2; count++} END {print sum/count}' data.txt# 最大值/最小值$ awk 'BEGIN{max=-999999} {if($2>max) max=$2} END {print max}' data.txt$ awk 'BEGIN{min=999999} {if($2<min) min=$2} END {print min}' data.txt# 分组统计$ awk '{sum[$1]+=$2} END {for(k in sum) print k, sum[k]}' data.txt$ awk '{count[$4]++} END {for(k in count) print k, count[k]}' access.log192.168.1.1 1523192.168.1.2 987# 多字段分组$ awk '{sum[$1,$2]+=$3} END {for(k in sum) print k, sum[k]}' data.txt

格式化输出

# printf 格式化$ awk 'BEGIN {printf "%-20s %10s\n", "Name", "Value"}           {printf "%-20s %10d\n", $1, $2}' data.txtName                    Valueitem1                       100item2                       200# 数字格式化$ awk '{printf "%.2f\n", $1}' decimals.txt# 自定义输出分隔符$ awk 'BEGIN {OFS=","} {print $1, $2}' data.txt# 自定义输出记录分隔符$ awk 'BEGIN {ORS="\n\n"} {print $1, $2}' data.txt# 日期时间格式化$ awk '{print strftime("%Y-%m-%d %H:%M:%S"), $0}' app.log

多文件处理

# 处理多个文件,在每个文件开始时打印文件名$ awk 'FNR==1 {print "=== " FILENAME " ==="} {print}' file1.txt file2.txt=== file1.txt ===content1content2=== file2.txt ===content3# 文件关联:FNR==NR 处理第一个文件,之后处理其他文件$ awk 'NR==FNR {map[$1]=$2; next} {print $0, map[$1]}' file1 file2# 合并两个文件$ awk 'NR==FNR {a[NR]=$0; next} {print a[NR], $0}' file1 file2# 计算两个文件的差异$ awk 'NR==FNR {a[$0]++; next} !($0 in a)' file1 file2

3.4 组合技:管道与脚本

日志分析组合

# 统计错误分布$ grep "ERROR" app.log | awk '{print $4}' | sort | uniq -c | sort -rn    15 connection_timeout    10 database_error     5 file_not_found     3 authentication_failed# 找出最慢的请求$ awk -F'"''$2 ~ /POST/ {print $4}' access.log | awk '{print $2}' | sort -rn | head -105.2344.5673.8902.1231.987# 实时监控新错误(使用 --line-buffered 强制行缓冲)$ tail -f app.log | grep --line-buffered "ERROR" | whileread line; doecho"$(date '+%Y-%m-%d %H:%M:%S')$line"done# 分析HTTP状态码分布$ awk '{print $5}' access.log | sort | uniq -c | sort -rn  15234 200   2341 404    523 500    312 302     89 403# 提取访问最频繁的URL$ awk -F'"''{print $2}' access.log | awk '{print $2}' | sort | uniq -c | sort -rn | head -10  1523 /api/users   987 /api/products   456 /static/css/main.css   234 /api/orders

大文件处理

# 分割大日志文件$ split -l 100000 app.log part_$ ls part_*part_aa  part_ab  part_ac  part_ad# 并行处理$ cat largefile | xargs -P4 -I{} grep "pattern" {}# 使用 xargs 加速 grep$ grep -rl "ERROR" /var/log/ | xargs -P4 -I{} grep -c "FATAL" {}# 流式压缩$ awk '{print $0}' app.log | gzip > app.log.gz# 分块处理大文件$ awk 'NR==1,NR==10000 {print} NR==10001 {exit}' largefile.log# 使用 awk 代替部分管道操作,减少进程创建开销# 低效:cat file | grep pattern | awk '{print $2}'# 高效:awk '/pattern/ {print $2}' file

3.5 排障场景实战

场景1:从海量日志中提取关键信息

问题描述:生产环境的nginx访问日志达到20GB,需要在不影响服务器性能的情况下,提取以下信息:

  • 所有状态码为500的请求
  • 提取这些请求的来源IP、时间、URL和响应时间
  • 统计每个IP的错误请求数量

解决方案

# 步骤1:提取500错误请求的关键信息$ awk -F'"''$3 ~ / 500 / {print $1, $4, $6, $NF}' access.log | \  awk '{print $1, $2, $3, $NF}' | \  sed 's/ - / /g'# 预期输出示例:192.168.1.105 [24/Apr/2026:10:15:32 +0800] GET /api/users HTTP/1.1 5.234192.168.1.203 [24/Apr/2026:10:16:45 +0800] POST /api/orders HTTP/1.1 12.345# 步骤2:统计每个IP的错误请求数量$ awk -F'"''$3 ~ / 500 / {print $1}' access.log | \  awk '{print $1}' | sort | uniq -c | sort -rn# 预期输出示例:    45 192.168.1.105    32 192.168.1.203    18 192.168.1.87     5 10.0.0.15# 步骤3:完整的一步到位命令$ awk -F'"''$3 ~ / 500 / {    ip=$1;    gsub(/^[[:space:]]+|[[:space:]]+$/, "", ip);    split($4, time, " ");    split(time[2], parts, ":");    printf "%s %s:%s:%s %s %sms\n", ip, parts[1], parts[2], parts[3], $6, $NF}' access.log | sort -k4 -rn | head -20# 预期输出示例:192.168.1.105 10:15:32 GET 5234ms192.168.1.203 10:16:45 POST 12345ms192.168.1.87 10:18:23 GET 8921ms

场景2:Java堆栈日志解析

问题描述:Java应用的error.log包含大量异常堆栈,需要快速定位以下信息:

  • 所有java.net.SocketException异常
  • 每个异常出现的次数和首次出现时间
  • 异常的调用链路

解决方案

# 步骤1:提取SocketException异常$ grep -A 20 "java.net.SocketException" error.log > socket_exceptions.txt# 步骤2:提取异常类型和行号$ grep -n "Exception\|Error" error.log | grep -E "^[0-9]+:( at | )" | head -30# 预期输出示例:456:java.net.SocketException: Connection reset   at java.net.SocketInputStream.read(SocketInputStream.java:210)   at java.net.SocketInputStream.read(SocketInputStream.java:122)   at java.io.BufferedInputStream.fill(BufferedInputStream.java:256)# 步骤3:统计异常出现次数$ grep -o "Exception:.*" error.log | sed 's/:.*//g' | sort | uniq -c | sort -rn# 预期输出示例:    45 SocketException    23 NullPointerException    12 IOException     8 IllegalArgumentException# 步骤4:提取关键调用栈(简化输出)$ awk '/Exception/ {ex=$0}       / at / && ++count<=3 {print ex, $0; ex=""}' error.log# 预期输出示例:java.net.SocketException: Connection reset at java.net.SocketInputStream.readjava.net.SocketException: Connection reset at com.app.ConnectionHandler.processjava.net.SocketException: Connection reset at com.app.RequestHandler.run

场景3:批量配置文件处理

问题描述:需要将100台服务器的nginx配置文件中的 keepalive_timeout 从65秒修改为120秒,同时将 client_max_body_size 从10M改为50M。

解决方案

# 步骤1:先在一台服务器上测试修改命令$ sed -i.bak \    -e 's/keepalive_timeout\s*65s;/keepalive_timeout 120s;/' \    -e 's/client_max_body_size\s*10M;/client_max_body_size 50M;/' \    /etc/nginx/nginx.conf# 步骤2:验证修改结果$ grep -E "keepalive_timeout|client_max_body_size" /etc/nginx/nginx.confkeepalive_timeout 120s;client_max_body_size 50M;# 步骤3:在所有服务器上批量执行(假设使用ansible或pssh)$ ansible all -m copy -a "src=nginx.conf dest=/etc/nginx/nginx.conf"$ ansible all -m service -a "name=nginx state=reloaded"# 或者使用pssh$ pssh -h hosts.txt -i "sed -i.bak \    -e 's/keepalive_timeout\s*65s;/keepalive_timeout 120s;/' \    -e 's/client_max_body_size\s*10M;/client_max_body_size 50M;/' \    /etc/nginx/nginx.conf && nginx -t && nginx -s reload"# 步骤4:验证所有服务器的配置一致性$ ansible all -m shell -a "grep -E 'keepalive_timeout|client_max_body_size' /etc/nginx/nginx.conf"# 预期输出示例(所有服务器):10.0.0.1 | SUCCESS | rc=0 | keepalive_timeout 120s; client_max_body_size 50M;10.0.0.2 | SUCCESS | rc=0 | keepalive_timeout 120s; client_max_body_size 50M;...

场景4:系统日志时间范围过滤

问题描述:需要从系统日志中提取2026年4月24日14:00至15:00之间的所有WARNING和ERROR级别日志,并按时间排序输出。

解决方案

# 方法1:使用awk的时间范围匹配$ awk '/^Apr 24 1[45]:/ && /WARNING\|ERROR/ {print}' /var/log/syslog | sort# 预期输出示例:Apr 24 14:15:32 server01 kernel: WARNING: memory usage at 85%Apr 24 14:23:45 server01 systemd[1]: ERROR: service apache2 failedApr 24 14:45:12 server01 application[1234]: WARNING: slow query detectedApr 24 15:00:00 server01 kernel: ERROR: disk I/O error# 方法2:使用awk解析时间戳进行数值比较$ awk '{    # 解析时间戳 Apr 24 HH:MM:SS    match($1" "$2" "$3, /([A-Za-z]+) ([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/, arr)    hour=arr[3]; minute=arr[4]    # 时间范围 14:00-15:00    if ((hour=="14" || hour=="15") && $5 ~ /WARNING|ERROR/)        print}' /var/log/syslog# 方法3:使用sed先标记范围,再用awk处理$ sed -n '/Apr 24 14:/,/Apr 24 15:/p' /var/log/syslog | \    awk '/WARNING|ERROR/'

场景5:Nginx日志数据提取与报表生成

问题描述:需要从nginx访问日志生成每小时的流量报表,包含以下指标:

  • 每小时请求数
  • 每小时总流量(bytes)
  • 每小时错误率(4xx+5xx)
  • 访问量Top 10的IP

解决方案

# 完整报表生成脚本$ cat > generate_report.awk << 'EOF'BEGIN {    FS = "\"";printf"%-10s %10s %15s %10s %15s\n""Hour""Requests""Traffic(Bytes)""Error%""TopIP"printf"------------------------------------------------------------\n"}{    hour = substr($2, 2, 13)  # 提取时间,如 [24/Apr/2026:14# 请求数    count[hour]++# 流量(从$3获取,如 "200 1234 "-")    split($3, parts, " ")    traffic[hour] += parts[2]# 错误请求    status = parts[1]if (status ~ /^[45][0-9][0-9]$/) {        errors[hour]++    }# IP统计    ip = $1    ipcount[hour,ip]++}# 找出每小时的Top IPNR > 1 && FNR == 1 {# 处理前一个文件的汇总for (h in count) {printf"%-10s %10d %15d %10.2f%%\n", h, count[h], traffic[h], (errors[h]/count[h]*100)    }# 重新初始化    delete count    delete traffic    delete errors    delete ipcount}END {# 排序输出    n = asort(count, sorted_hours)for (i = 1; i <= n; i++) {        h = sorted_hours[i]# 找Top IP        topip = ""        maxcount = 0for (key in ipcount) {            split(key, kv, SUBSEP)if (kv[1] == h && ipcount[key] > maxcount) {                maxcount = ipcount[key]                topip = kv[2]            }        }printf"%-10s %10d %15d %10.2f%% %s(%d)\n",            h, count[h], traffic[h], (errors[h]/count[h]*100), topip, maxcount    }}EOF# 运行报表生成$ awk -f generate_report.awk access.log | sort# 预期输出示例:Hour      Requests     Traffic(Bytes)   Error%     TopIP------------------------------------------------------------24/Apr/2026:00       1523        15234567      2.34% 192.168.1.10(156)24/Apr/2026:01       1234        12345678      1.87% 192.168.1.15(123)...

四、生产环境最佳实践

4.1 脚本规范化

shebang与跨平台

脚本开头的shebang行决定了脚本的解释器选择,对于确保脚本的可移植性至关重要:

# 推荐使用 env 获取标准路径,增强可移植性#!/usr/bin/env bash# 明确指定bash版本需求(如果需要特定功能)#!/usr/bin/env bash# Bash version 4.0+ required for associative arrays# 对于awk脚本#!/usr/bin/env awk -f# 或者明确指定#!/bin/bash#!/usr/bin/awk -f

参数校验与帮助信息

生产环境脚本必须包含完善的参数校验和帮助信息:

#!/usr/bin/env bash# 脚本用途说明USAGE="Usage: $0 [-f FILE] [-t TYPE] [-h]Extract and analyze error patterns from log files.Options:    -f FILE     Log file to process (required)    -t TYPE     Error type filter: error|warning|fatal (default: all)    -n NUM      Number of results to display (default: 10)    -h          Show this help messageExamples:$0 -f /var/log/app.log -t error -n 20$0 -f /var/log/app.log --type fatal"# 解析参数whilegetopts":f:t:n:h" opt; docase$optin        f) FILE="$OPTARG" ;;        t) TYPE="$OPTARG" ;;        n) NUM="$OPTARG" ;;        h) echo"$USAGE"exit 0 ;;        \?) echo"Invalid option: -$OPTARG" >&2; echo"$USAGE" >&2; exit 1 ;;        :) echo"Option -$OPTARG requires an argument." >&2; exit 1 ;;esacdone# 必需参数校验if [[ -z "$FILE" ]]; thenecho"Error: -f FILE is required" >&2echo"$USAGE" >&2exit 1fi# 文件存在性校验if [[ ! -f "$FILE" ]]; thenecho"Error: File '$FILE' does not exist" >&2exit 1fi# 默认值设置TYPE="${TYPE:-all}"NUM="${NUM:-10}"

日志与错误处理

#!/usr/bin/env bash# 日志函数log_info() {echo"[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $*"}log_error() {echo"[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $*" >&2}log_warn() {echo"[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $*" >&2}# 错误处理函数set -euo pipefail  # 严格模式trap'on_error $? $LINENO' ERRon_error() {    log_error "Command failed with exit code $1 at line $2"    log_error "Last command: $BASH_COMMAND"exit$1}# 测试运行log_info "Starting log analysis"if grep -q "ERROR""$FILE"then    log_warn "Found errors in $FILE"filog_info "Analysis complete"

性能优化技巧

#!/usr/bin/env bash# 场景:处理大文件时使用更高效的方法# 技巧1:避免子shell,减少进程创建# 低效:# cat file | grep pattern | awk '{print $2}'# 高效:# grep pattern file | awk '{print $2}'# 或更高效:# awk '/pattern/ {print $2}' file# 技巧2:使用单pass完成多次操作# 低效:# grep "ERROR" app.log > errors.txt# grep "WARNING" app.log > warnings.txt# 高效:# awk '/ERROR/ {print > "errors.txt"} /WARNING/ {print > "warnings.txt"}' app.log# 技巧3:提前过滤,减少处理数据量# 低效:# cat largefile | awk '{print $1, $2}' | grep "pattern"# 高效:# awk '/pattern/ {print $1, $2}' largefile# 技巧4:避免在循环中进行正则匹配# 低效:# while read line; do#     echo "$line" | grep "pattern"# done < file# 高效:# grep "pattern" file

4.2 常见陷阱与规避

陷阱1:grep的-o选项只输出匹配部分

# 问题:-o 只输出匹配的部分,而不是整行echo"error123" | grep "error"error123echo"error123" | grep -o "error"error# 如果需要提取匹配部分并保留上下文,需要结合其他工具echo"2026-04-24 error: connection failed" | grep -oP '.{0,20}error.{0,20}'2026-04-24 error: connection failed# 或者使用awk的match函数echo"2026-04-24 error: connection failed" | awk '{if(match($0, /.{0,20}error.{0,20}/)) print substr($0, RSTART, RLENGTH)}'2026-04-24 error: connection failed

陷阱2:sed的-i选项不可恢复

# 问题:-i 直接修改文件,没有后悔药$ sed -i 's/old/new/g' important.txt# 解决方案1:使用 -i.bak 创建备份$ sed -i.bak 's/old/new/g' important.txt# 原文件保存为 important.txt.bak# 解决方案2:先输出到临时文件,确认后再覆盖$ sed 's/old/new/g' important.txt > important.txt.tmp$ diff important.txt important.txt.tmp  # 确认差异$ mv important.txt.tmp important.txt# 解决方案3:在脚本中使用安全模式sed_editor() {local file="$1"local pattern="$2"local replacement="$3"# 创建临时副本    cp "$file""${file}.backup.$(date +%s)"# 执行替换    sed "s/${pattern}/${replacement}/g""$file" > "${file}.tmp"# 确认后替换if [[ -s "${file}.tmp" ]]; then        mv "${file}.tmp""$file"echo"Modified: $file"elseecho"Error: Result is empty, keeping original" >&2        rm -f "${file}.tmp"exit 1fi}

陷阱3:awk的FS与OFS区别

# 问题:FS(输入字段分隔符)和 OFS(输出字段分隔符)容易混淆# FS: 控制如何将输入行分割成字段# OFS: 控制输出时字段之间的分隔符# 示例:处理以逗号分隔的CSV,输出时用空格分隔echo"a,b,c,d" | awk -F',''{print $1, $3}' OFS=' 'a c# 默认 OFS 是空格,所以上面的输出是 "a c"# 如果想用逗号分隔:echo"a,b,c,d" | awk -F',''{print $1, $3}' OFS=','a,c# 常见错误:忘记设置 FS,导致字段分割不正确echo"2026-04-24 10:15:32" | awk '{print $1}'# 默认按空格分割2026-04-24echo"2026-04-24 10:15:32" | awk -F'[: ]''{print $1, $4}'# 按冒号和空格分割2026-04-24 10# 使用 FPAT 更精确地定义字段(匹配字段内容而非分隔符)echo'"field1","field2","field3"' | awk 'BEGIN{FPAT="[^,]+|\\"[^\\"]*\\""} {print $2}'"field2"

陷阱4:正则的贪心匹配问题

# 问题:正则表达式默认贪心匹配,可能匹配超出预期的内容# 示例:提取 HTML 标签内容echo"<div>text1</div><div>text2</div>" | grep -oP '<div>.*</div>'<div>text1</div><div>text2</div># 匹配了从第一个<div>到最后一个</div>的所有内容# 解决方案1:使用非贪婪匹配(.+? 或 .*?)echo"<div>text1</div><div>text2</div>" | grep -oP '<div>.*?</div>'<div>text1</div><div>text2</div># 解决方案2:使用排除字符类echo"<div>text1</div><div>text2</div>" | grep -oP '<div>[^<]+</div>'<div>text1</div><div>text2</div># 示例:sed 替换中的贪心匹配echo"a b c d a b" | sed 's/a.*b/REPLACED/'REPLACED  # 匹配从第一个 a 到最后一个 becho"a b c d a b" | sed 's/a.*?b/REPLACED/'REPLACED c d REPLACED# awk 中的贪心匹配echo"abc123def456" | awk '{gsub(/[0-9]+/, "NUM"); print}'abcNUMdefNUM# 这是正确的,因为 gsub 默认替换所有匹配# 但如果想只替换第一个:echo"abc123def456" | awk '{gsub(/[0-9]+/, "NUM", $0); print}'# 还是全部替换echo"abc123def456" | awk '{$0 = substr($0, 1, match($0, /[0-9]+/)-1) "NUM" substr($0, RSTART+RLENGTH); print}'abcNUMdef456

陷阱5:特殊字符在正则和shell中的转义

# 问题:shell的变量展开和正则的元字符冲突# 示例:想要匹配字面量 $echo"price: $100" | grep "$100"# 报错:$1 是未定义的shell变量# 正确做法:使用单引号防止shell展开echo"price: $100" | grep '\$100'price: $100# 或者转义echo"price: $100" | grep "\$100"price: $100# sed 中的反斜杠处理# 在 sed 替换中,& 代表匹配内容,所以如果真的要替换 & 字符:echo"a&b" | sed 's/&/and/'aandb# 要匹配字面量 &,需要转义echo"a&b" | sed 's/\&/and/'aandb# 或者echo"a&b" | sed 's/\&/and/'aandb# awk 中的转义echo"price: $100" | awk '{gsub(/\$/, "USD"); print}'price: USD100# 复杂正则中的多重转义# 在 shell 字符串中,反斜杠本身也需要转义# 匹配字面量 [abc](包括方括号)echo"[abc]" | grep -F '[abc]'# -F 禁用正则,直接匹配字面量[abc]echo"[abc]" | grep '\[abc\]'# 需要转义方括号[abc]echo"[abc]" | awk '/\[abc\]/'# awk 中也需要转义[abc]

4.3 效率优化

避免piping:用awk代替grep+sed组合

# 低效:创建多个进程,管道数据传输开销大$ cat app.log | grep "ERROR" | sed 's/\[ERROR\]/Error:/' | awk '{print $1, $2, $3}'# 高效:用awk单次遍历完成所有操作$ awk '/ERROR/ {sub(/\[ERROR\]/, "Error:"); print $1, $2, $3}' app.log# 性能测试对比(处理100MB日志)$ time cat app.log | grep "ERROR" | sed 's/\[ERROR\]/Error:/' | awk '{print $1, $2, $3}' > /dev/null# real    0m5.234s$ time awk '/ERROR/ {sub(/\[ERROR\]/, "Error:"); print $1, $2, $3}' app.log > /dev/null# real    0m2.156s

预编译正则:awk 'BEGIN{pattern=...}'

# 在awk的BEGIN块中预定义正则,可以提高循环处理效率$ cat process_logs.awkBEGIN {    error_pat = "ERROR|WARN|FATAL"    time_pat = "[0-9]{4}-[0-9]{2}-[0-9]{2}"}$0 ~ error_pat && $0 ~ time_pat {# 处理逻辑print}# 或者使用正则常量$ awk 'BEGIN{pattern=/^[0-9]{4}-[0-9]{2}-[0-9]{2}/} $0 ~ pattern {print}' app.log# 对于多次使用相同正则的情况$ awk '{    if (/ERROR/ && /2026-04-24/ && /14:/) {        count++    }}END {print count}' app.log# 可以简化为(awk支持正则作为模式)$ awk '/ERROR/ && /2026-04-24/ && /14:/ {count++} END {print count}' app.log

增量处理:只读取需要的部分

# 场景:只需要文件的前1000行# 低效:读取整个文件,然后取前1000行$ awk '{print}' app.log | head -1000# 高效:提前终止处理$ awk 'NR<=1000 {print} NR==1000 {exit}' app.log# 场景:跳过前面的内容,从特定行开始$ awk 'NR>=100000 {print} NR==200000 {exit}' app.log# 场景:只处理包含特定关键词的行,无需遍历全文$ awk '/ERROR/ {process} /DONE/ {exit}' app.log# 场景:使用exit处理异常情况$ awk '    /ERROR/ {error_count++}    error_count > 100 {print "Too many errors, aborting"; exit 1}    END {print "Total errors:", error_count}' app.log

多核利用:parallel/xargs -P

# GNU parallel:并行执行任务$ cat urls.txt | parallel -j4 'curl -s {} | grep -o "title>.*<" | head -1'# xargs -P:并行处理$ find /var/log -name "*.log" -print0 | \    xargs -0 -P4 -I{} grep -l "ERROR" {} | \    xargs -P2 -I{} awk '/ERROR/ {count++} END {print FILENAME, count}' {}# parallel 更高级的用法$ parallel -j200% --plus --pipe --cat --block 10M \'awk "/ERROR/{count++} END{print count}"' ::: *.log# 使用 awk 的并行处理能力(gawk 5.3+)$ gawk -M 'BEGIN {for(i=1;i<=1000000000;i++) s+=sqrt(i)} END {print s}'# 性能对比(处理10个1GB日志文件)$ time ls *.log | xargs -P1 -I{} awk '/ERROR/ {count++} END {print FILENAME, count}' {}# real    0m32.456s$ time ls *.log | xargs -P10 -I{} awk '/ERROR/ {count++} END {print FILENAME, count}' {}# real    0m4.123s

五、扩展阅读与证据链

5.1 官方文档

GNU grep manual

  • 官方文档地址:https://www.gnu.org/software/grep/manual/
  • 最新稳定版本:3.11(截至2026年4月)
  • 关键章节:
    • 2.2 "Matches":正则表达式匹配规则详解
    • 3.2 "Command-line Options":所有命令行选项说明
    • 5.1 "Performance":性能优化指南

GNU sed manual

  • 官方文档地址:https://www.gnu.org/software/sed/manual/
  • 最新稳定版本:4.9(截至2026年4月)
  • 关键章节:
    • 3.1 "Execution Cycle":sed执行周期详解
    • 4.1 "sed Addresses":地址寻址方式
    • 5.1 "The s Command":替换命令详解

GNU awk manual (GAWK)

  • 官方文档地址:https://www.gnu.org/software/gawk/manual/
  • 最新稳定版本:5.3(截至2026年4月)
  • 关键章节:
    • 2.2 "Regular Expressions":正则表达式深度解析
    • 7.4 "Variables":内置变量详解
    • 9.3 "Built-in Functions":内置函数参考
    • 12.1 "Array Sorting":数组排序功能

POSIX标准参考

  • POSIX.1-2017定义了grep、sed、awk的标准行为
  • IEEE Std 1003.1-2017:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/
  • 遵循POSIX标准可以确保脚本在不同Unix系统间的可移植性

5.2 经典参考书

《sed & awk》

  • 作者:Dale Dougherty, Arnold Robbins
  • 最新版本:2nd Edition (1997),但内容仍然适用
  • O'Reilly 出版
  • 评价:被视为sed和awk的权威指南,深度解析了两种工具的设计理念和使用技巧

《Regular Expressions Mastery》

  • 作者:Adam Ahmed
  • 出版年份:2024年
  • 平台:Pluralsight/Manning
  • 内容:现代正则表达式实战,涵盖PCRE、regex模块性能优化

《Linux命令行与shell脚本编程大全》

  • 作者:Richard Blum, Christine Bresnahan
  • 最新版本:4th Edition (2021)
  • 出版社:Sybex
  • 相关章节:第20-23章详细讲解了三剑客的实战应用

5.3 在线资源

grep/sed/awk速查表

  • https://quickref.me/sed
  • https://quickref.me/awk
  • https://quickref.me/regex

正则表达式测试工具

  • https://regex101.com/:支持PCRE、Python、JavaScript等多种方言
  • https://regexr.com/:提供实时匹配和解释功能
  • https://www.debuggex.com/:可视化正则表达式匹配过程

性能基准测试

  • https://github.com/google/benchmark:用于测试不同文本处理方法的性能
  • 自建基准测试:使用 time 命令和 /usr/bin/time -v 进行精确计时

六、自检清单

附录A:命令快速参考

A.1 grep 常用选项速查

选项
说明
示例
-i
忽略大小写
grep -i "error" file
-n
显示行号
grep -n "error" file
-c
统计匹配行数
grep -c "error" file
-v
反向匹配
grep -v "DEBUG" file
-r
递归搜索
grep -r "error" dir/
-l
只显示文件名
grep -rl "error" dir/
-o
只输出匹配部分
grep -o "error[0-9]*" file
-e
指定多个模式
grep -e "error" -e "warn" file
-E
扩展正则
grep -E "error|warn" file
-P
Perl正则
grep -P "\d{4}-\d{2}" file
-F
固定字符串
grep -F "exact.string" file
-A n
显示后n行
grep -A5 "error" file
-B n
显示前n行
grep -B3 "error" file
-C n
显示前后n行
grep -C3 "error" file

A.2 sed 常用命令速查

命令
说明
示例
s/old/new/
替换第一个
sed 's/old/new/' file
s/old/new/g
全部替换
sed 's/old/new/g' file
s/old/new/2
替换第2个
sed 's/old/new/2' file
d
删除行
sed '/error/d' file
p
打印行
sed -n '5p' file
i\text
行前插入
sed '1i\line0' file
a\text
行后追加
sed '1a\line2' file
c\text
替换整行
sed '2c\changed' file
y/a/b/
字符转换
sed 'y/aeiou/12345/'
q
退出
sed '10q' file
r file
读文件
sed '5r add.txt' file
w file
写文件
sed -n 'w out.txt' file
n
下一行
sed 'n;d' file
N
追加下一行
sed 'N;s/\n/ /' file

A.3 awk 常用内置变量和函数

变量/函数
说明
$0
整行
n
第n个字段
NF
字段数
NR
记录号(全局)
FNR
文件内记录号
FS
输入字段分隔符
OFS
输出字段分隔符
RS
输入记录分隔符
ORS
输出记录分隔符
FILENAME
当前文件名
print
打印
printf
格式化打印
length(s)
字符串长度
substr(s,i,n)
截取子串
split(s,a,sep)
分割字符串
gsub(r,t,s)
全局替换
match(s,r)
正则匹配
systime()
当前时间戳
strftime(fmt)
格式化时间

附录B:正则表达式速查

B.1 字符类

模式
匹配
[abc]
a、b、c中的任意一个
[^abc]
除a、b、c外的任意字符
[a-z]
a到z的任意小写字母
[A-Z]
A到Z的任意大写字母
[0-9]
任意数字
[:alnum:]
字母和数字
[:alpha:]
字母
[:digit:]
数字
[:lower:]
小写字母
[:upper:]
大写字母
[:space:]
空白字符

B.2 量词

量词
匹配
*
零个或多个
+
一个或多个
?
零个或一个
{n}
恰好n个
{n,}
至少n个
{n,m}
n到m个

B.3 锚点

锚点
匹配位置
^
行首
$
行尾
\b
词边界
\B
非词边界

B.4 环视断言(PCRE)

断言
含义
(?=pattern)
后面是pattern
(?!pattern)
后面不是pattern
(?<=pattern)
前面是pattern
(?<!pattern)
前面不是pattern

附录C:常见问题排查

C.1 grep常见问题

Q: 为什么 grep -o 只返回匹配部分而不是整行?A: -o 选项的设计就是只输出匹配的部分。如果需要整行输出,去掉 -o 选项即可。

Q: 为什么 grep 在大文件上很慢?A: 可能的原因:使用了复杂的正则表达式、没有使用锚点、开启了大小写不敏感匹配(-i)。优化方法:使用 -F 进行字符串匹配、使用 ^ 锚定行首、使用 --binary-files=without-match 跳过二进制文件。

Q: grep 正则表达式不生效?A: 检查是否使用了正确的正则模式。grep 默认使用 BRE,需要转义 +?| 等元字符;使用 -E 启用 ERE;使用 -P 启用 PCRE。

C.2 sed常见问题

Q: sed 替换不生效?A: 常见原因:没有加 -i 选项修改文件、分隔符与内容冲突(可用其他符号如 | 或 # 代替 /)、正则表达式语法错误。

Q: sed 如何替换包含斜杠的路径?A: 使用其他分隔符,如 sed 's#/old/path#/new/path#' file 或转义斜杠 sed 's/\/old\/path/\/new\/path/' file

Q: sed 的 & 是什么意思?A: & 在替换字符串中代表匹配到的内容。例如 sed 's/word/"&"/' file 会给所有 "word" 加上引号变成 "word"

C.3 awk常见问题

Q: awk 如何处理逗号分隔的CSV文件?A: 使用 -F',' 指定逗号作为字段分隔符。注意:如果CSV字段内包含逗号,需要使用 FPAT 或更复杂的解析逻辑。

Q: awk 中如何判断数组键是否存在?A: 使用 if (key in array) 检查键是否存在,但不能直接用 array[key] 来判断(访问不存在的键会创建该键)。

Q: awk 如何输出到文件而不是屏幕?A: 使用 print > "filename" 重定向输出;使用 close("filename") 关闭文件。也可以使用 fflush() 刷新缓冲区。


本文档由资深运维架构师编写,基于十余年一线经验总结。文档内容经过生产环境验证,适用于Linux系统运维、DevOps工程师、SRE等专业人员参考使用。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 21:43:39 HTTP/2.0 GET : https://f.mffb.com.cn/a/489446.html
  2. 运行时间 : 0.103609s [ 吞吐率:9.65req/s ] 内存消耗:4,978.90kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=9ea9d2839695cca92d2bd57fa58c5623
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000529s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000846s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000445s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000305s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000518s ]
  6. SELECT * FROM `set` [ RunTime:0.000222s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000598s ]
  8. SELECT * FROM `article` WHERE `id` = 489446 LIMIT 1 [ RunTime:0.000716s ]
  9. UPDATE `article` SET `lasttime` = 1783086219 WHERE `id` = 489446 [ RunTime:0.018486s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000259s ]
  11. SELECT * FROM `article` WHERE `id` < 489446 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000556s ]
  12. SELECT * FROM `article` WHERE `id` > 489446 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000454s ]
  13. SELECT * FROM `article` WHERE `id` < 489446 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001017s ]
  14. SELECT * FROM `article` WHERE `id` < 489446 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.006559s ]
  15. SELECT * FROM `article` WHERE `id` < 489446 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000934s ]
0.105271s