三亚市网站建设_网站建设公司_Angular_seo优化
2026/1/9 14:01:56 网站建设 项目流程

前言

grep、sed、awk 被称为 Linux 文本处理三剑客。日志分析、数据提取、批量替换……日常运维离不开这三个工具。很多人只会基础用法,遇到复杂需求就抓瞎。

本文整理三剑客的实用技巧,从基础语法到实际场景,配合大量示例。


1. grep:文本搜索

1.1 基础用法

# 基本搜索grep"error"app.log# 忽略大小写grep-i"error"app.log# 显示行号grep-n"error"app.log# 显示匹配行的前后文grep-A3"error"app.log# 后3行grep-B3"error"app.log# 前3行grep-C3"error"app.log# 前后各3行# 递归搜索目录grep-r"TODO"src/# 只显示文件名grep-l"error"*.log# 统计匹配次数grep-c"error"app.log# 反向匹配(不包含)grep-v"debug"app.log

1.2 正则表达式

# 基础正则(BRE)grep"^start"file# 以start开头grep"end$"file# 以end结尾grep"a.b"file# a和b之间有任意字符grep"ab*"file# a后面有0个或多个b# 扩展正则(ERE)grep-E"error|warn"file# 或grep-E"ab+"file# a后面有1个或多个bgrep-E"ab?"file# a后面有0个或1个bgrep-E"a{2,4}"file# 2到4个agrep-E"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"file# IP地址# Perl正则(更强大)grep-P"\d{4}-\d{2}-\d{2}"file# 日期格式grep-P"(?<=user:)\w+"file# 零宽断言

1.3 实用场景

# 搜索日志中的错误grep-E"(ERROR|FATAL)"app.log|tail-20# 搜索特定时间段的日志grep"2025-01-08 10:"app.log# 搜索IP地址grep-oE"\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"access.log# 统计每个IP的访问次数grep-oE"\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"access.log|sort|uniq-c|sort-rn|head# 搜索多个关键词(都包含)grep"error"app.log|grep"database"# 排除某些文件grep-r"password"--include="*.py"--exclude="*test*"src/# 只显示匹配的内容(不是整行)grep-o"user_id=[0-9]*"app.log

2. sed:流编辑器

2.1 基础替换

# 替换第一个匹配sed's/old/new/'file# 替换所有匹配sed's/old/new/g'file# 忽略大小写sed's/old/new/gi'file# 直接修改文件(危险操作,建议先备份)sed-i's/old/new/g'filesed-i.bak's/old/new/g'file# 自动备份# 只处理特定行sed'5s/old/new/g'file# 第5行sed'1,10s/old/new/g'file# 1-10行sed'/pattern/s/old/new/g'file# 匹配pattern的行

2.2 删除操作

# 删除特定行sed'5d'file# 删除第5行sed'1,10d'file# 删除1-10行sed'/pattern/d'file# 删除匹配的行sed'/^$/d'file# 删除空行sed'/^#/d'file# 删除注释行# 删除行首/行尾空格sed's/^[ \t]*//'file# 行首sed's/[ \t]*$//'file# 行尾sed's/^[ \t]*//;s/[ \t]*$//'file# 两端

2.3 插入和追加

# 在第3行后插入sed'3a\新内容'file# 在第3行前插入sed'3i\新内容'file# 在匹配行后插入sed'/pattern/a\新内容'file# 替换整行sed'3c\新的一行'filesed'/pattern/c\新的一行'file

2.4 高级用法

# 使用分组和引用sed's/\(.*\):\(.*\)/\2:\1/'file# 交换冒号两边的内容# 多个替换sed-e's/a/A/g'-e's/b/B/g'filesed's/a/A/g; s/b/B/g'file# 打印特定行sed-n'5p'file# 只打印第5行sed-n'5,10p'file# 只打印5-10行sed-n'/pattern/p'file# 只打印匹配行# 使用变量old="foo"new="bar"sed"s/$old/$new/g"file# 注意用双引号# 使用不同的分隔符(处理路径时有用)sed's|/usr/local|/opt|g'filesed's#/usr/local#/opt#g'file

2.5 实用场景

# 修改配置文件sed-i's/^#Port 22/Port 2222/'/etc/ssh/sshd_config# 批量替换文件内容find.-name"*.txt"-execsed-i's/old/new/g'{}\;# 删除HTML标签sed's/<[^>]*>//g'file.html# 提取两个标记之间的内容sed-n'/START/,/END/p'file# 在每行前面加行号sed=file|sed'N;s/\n/\t/'# 每行末尾追加内容sed's/$/ END/'file# 处理Windows换行符sed's/\r$//'filesed-i's/\r$//'file

3. awk:数据处理

3.1 基础语法

# 基本格式awk'pattern { action }'file# 打印特定列awk'{print $1}'file# 第1列awk'{print $1, $3}'file# 第1和第3列awk'{print $NF}'file# 最后一列awk'{print $(NF-1)}'file# 倒数第二列# 指定分隔符awk-F':''{print $1}'/etc/passwdawk-F',''{print $1, $2}'data.csv# 条件过滤awk'$3 > 100 {print $0}'fileawk'/error/ {print $0}'file

3.2 内置变量

变量含义
$0整行内容
1−1-1n第n个字段
NF字段数量
NR当前行号
FNR当前文件的行号
FS字段分隔符
OFS输出字段分隔符
RS记录分隔符
ORS输出记录分隔符
# 使用内置变量awk'{print NR, $0}'file# 带行号awk'NR==5'file# 第5行awk'NR>=5 && NR<=10'file# 5-10行awk'END {print NR}'file# 总行数

3.3 BEGIN和END

# BEGIN:处理前执行# END:处理后执行awk'BEGIN {print "开始"} {print $0} END {print "结束"}'file# 计算总和awk'BEGIN {sum=0} {sum+=$1} END {print "总和:", sum}'file# 计算平均值awk'{sum+=$1; count++} END {print "平均:", sum/count}'file# 设置输出分隔符awk'BEGIN {OFS=","} {print $1, $2, $3}'file

3.4 条件和循环

# if条件awk'{if ($3>100) print $1, "高"; else print $1, "低"}'file# for循环awk'{for(i=1; i<=NF; i++) print $i}'file# while循环awk'{i=1; while(i<=NF) {print $i; i++}}'file# 数组awk'{count[$1]++} END {for(k in count) print k, count[k]}'file

3.5 实用场景

# 统计日志中各状态码的数量awk'{print $9}'access.log|sort|uniq-c|sort-rn# 用awk实现awk'{status[$9]++} END {for(s in status) print s, status[s]}'access.log# 计算请求平均响应时间awk'{sum+=$NF; count++} END {print "平均响应时间:", sum/count, "ms"}'access.log# 找出响应时间最长的请求awk'BEGIN {max=0} {if($NF>max) {max=$NF; line=$0}} END {print line}'access.log# 统计每小时请求量awk-F'[: ]''{hour[$5]++} END {for(h in hour) print h":00", hour[h]}'access.log|sort# 提取特定格式的数据awk-F'"''/GET/ {print $2}'access.log|awk'{print $2}'|sort|uniq-c|sort-rn|head# 格式化输出awk'{printf "%-20s %10d\n", $1, $2}'file# 处理CSVawk-F',''{print $1, $3}'data.csv# 过滤并统计awk'/ERROR/ {count++; print} END {print "共", count, "个错误"}'app.log

3.6 复杂示例

# 日志分析:统计每个IP的请求量和流量awk'{ ip=$1 requests[ip]++ bytes[ip]+=$10 } END { printf "%-20s %10s %15s\n", "IP", "请求数", "流量(MB)" for(ip in requests) { printf "%-20s %10d %15.2f\n", ip, requests[ip], bytes[ip]/1024/1024 } }'access.log|sort-k2 -rn|head-20# 实时监控日志tail-f access.log|awk'/ERROR/ {print strftime("%Y-%m-%d %H:%M:%S"), $0}'# 多文件处理awk'FNR==1 {print "文件:", FILENAME} {print}'file1 file2# 关联数组实现joinawk-F',''NR==FNR {a[$1]=$2; next} {print $0, a[$1]}'file1 file2

4. 组合使用

4.1 管道组合

# grep + awk:先过滤再处理grep"ERROR"app.log|awk'{print $1, $2, $NF}'# grep + sed:先过滤再替换grep-l"old_api"*.py|xargssed-i's/old_api/new_api/g'# awk + sort + uniq:统计分析awk'{print $1}'access.log|sort|uniq-c|sort-rn|head-10# 完整的日志分析流程cataccess.log|\grep"2025-01-08"|\awk'$9==500 {print $1, $7}'|\sort|uniq-c|sort-rn|head-20

4.2 实战案例

案例1:分析Nginx访问日志

#!/bin/bash# nginx_log_analysis.shLOG_FILE="${1:-/var/log/nginx/access.log}"echo"=== Nginx日志分析 ==="echo"日志文件:$LOG_FILE"echo""echo"【请求总量】"wc-l<"$LOG_FILE"echo""echo"【状态码分布】"awk'{print $9}'"$LOG_FILE"|sort|uniq-c|sort-rnecho""echo"【Top 10 IP】"awk'{print $1}'"$LOG_FILE"|sort|uniq-c|sort-rn|head-10echo""echo"【Top 10 URL】"awk'{print $7}'"$LOG_FILE"|sort|uniq-c|sort-rn|head-10echo""echo"【4xx/5xx 错误】"awk'$9~/^[45]/ {print $9, $7}'"$LOG_FILE"|sort|uniq-c|sort-rn|head-10

案例2:批量修改配置文件

#!/bin/bash# update_config.shCONFIG_DIR="/etc/myapp"OLD_VALUE="localhost"NEW_VALUE="192.168.1.100"# 查找需要修改的文件echo"以下文件将被修改:"grep-rl"$OLD_VALUE""$CONFIG_DIR"read-p"确认修改?(y/n) "confirmif[["$confirm"=="y"]];thengrep-rl"$OLD_VALUE""$CONFIG_DIR"|xargssed-i.bak"s/$OLD_VALUE/$NEW_VALUE/g"echo"修改完成"fi

案例3:日志实时监控告警

#!/bin/bash# log_monitor.shLOG_FILE="/var/log/app/app.log"ERROR_THRESHOLD=10CHECK_INTERVAL=60whiletrue;do# 统计最近1分钟的错误数error_count=$(tail-1000"$LOG_FILE"|\awk-vtime=$(date -d'1 minute ago''+%Y-%m-%d %H:%M')\'$0 ~ time && /ERROR/ {count++} END {print count+0}')if[[$error_count-gt$ERROR_THRESHOLD]];thenecho"[$(date)] 告警: 最近1分钟错误数$error_count超过阈值$ERROR_THRESHOLD"# 发送告警fisleep$CHECK_INTERVALdone

5. 性能优化

5.1 大文件处理

# 使用LC_ALL=C提升性能LC_ALL=Cgrep"pattern"huge_file.log# 并行处理cathuge_file.log|parallel --pipegrep"pattern"# 分块处理split-l1000000huge_file.log chunk_forfinchunk_*;dogrep"pattern""$f"&donewait# 使用ripgrep(比grep快)rg"pattern"huge_file.log

5.2 避免常见陷阱

# 错误:多次读取文件count=$(grep-c"error"file)lines=$(grep"error"file)# 正确:一次读取result=$(grep"error"file)count=$(echo"$result"|wc-l)# 错误:不必要的catcatfile|grep"pattern"# 正确:直接读取grep"pattern"file# 错误:循环中频繁调用外部命令whilereadline;doecho"$line"|grep"pattern"done<file# 正确:一次性处理grep"pattern"file

总结

工具适用场景常用参数
grep搜索、过滤-i(忽略大小写) -n(行号) -r(递归) -E(正则) -v(反向)
sed替换、删除-i(原地修改) -n(静默) s/old/new/g(替换) d(删除)
awk列处理、统计-F(分隔符) NR(行号) NF(列数) $n(第n列)

使用原则

  1. 简单搜索用 grep
  2. 简单替换用 sed
  3. 列处理和统计用 awk
  4. 复杂场景组合使用

学习建议

  • 从简单用法开始,逐步掌握正则表达式
  • 多练习实际场景,比如日志分析
  • 遇到复杂需求先想清楚再写,避免过度嵌套

更多运维技术文章,欢迎关注公众号:北平的秋葵

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询