2708 words
14 minutes
grep,sed,awk详解
grep、sed、awk 详解:Unix 文本处理三剑客
在 Unix/Linux 系统中,grep、sed、awk 被誉为”文本处理三剑客”。这三个工具虽然诞生于上世纪 70 年代,但至今仍是系统管理员、开发者和运维工程师的必备利器。它们组合使用可以完成几乎所有文本处理任务。本文将详细介绍这三个工具的核心概念、常用命令和实战技巧。
grep:模式搜索工具
grep(Global Regular Expression Print)是最常用的文本搜索工具,它能够在文件中搜索符合指定模式的行,并将匹配的行输出到标准输出。
基本用法
# 在文件中搜索包含 "error" 的行grep "error" logfile.txt
# 搜索多个文件grep "TODO" *.py *.js
# 递归搜索目录grep -r "function" /path/to/code
# 显示行号grep -n "import" main.py常用选项
grep 提供了丰富的命令行选项来控制搜索行为:
# -i:忽略大小写grep -i "error" logfile.txt
# -v:反向匹配(不包含模式的行)grep -v "^#" config.conf
# -c:只显示匹配行数grep -c "print" script.py
# -l:只显示包含匹配内容的文件名grep -l "TODO" *.py
# -r:递归搜索目录grep -r "database" /path/to/project
# -n:显示行号grep -n "def" main.py
# -A、-B、-C:显示上下文grep -A 3 "error" logfile.txt # 显示匹配行后 3 行grep -B 3 "error" logfile.txt # 显示匹配行前 3 行grep -C 3 "error" logfile.txt # 显示匹配行前后各 3 行正则表达式支持
grep 支持两种正则表达式风格:
# 基本正则表达式(BRE)- 默认grep "file\.txt" files.txt
# 扩展正则表达式(ERE)- 使用 -E 或 egrepgrep -E "error|warning|info" logfile.txt
# 常用正则表达式元字符grep "^[0-9]" data.txt # 以数字开头grep "test$" result.txt # 以 test 结尾grep "a\{3,5\}" pattern.txt # 匹配 3-5 个 a(BRE)grep -E "a{3,5}" pattern.txt # 匹配 3-5 个 a(ERE)grep "[A-Z][a-z]+" names.txt # 大写字母开头后跟小写字母实用示例
# 查找进程ps aux | grep python
# 查找空日志文件find . -type f -empty | grep "\.log$"
# 统计代码行数grep -c "" *.py | awk -F: '{sum+=$2} END {print sum}'
# 查找包含特定 IP 的访问日志grep "192.168.1.100" access.log
# 查找以 # 开头的注释行grep "^#" config.conf
# 查找不包含注释的配置行grep -v "^#" config.conf | grep -v "^$"
# 查找 Git 仓库中的作者git log | grep "Author:"sed:流编辑器
sed(Stream Editor)是一个强大的文本流编辑器,它能对输入流(文件或管道)执行基本的文本转换操作。sed 以行为单位处理文本,适合批量修改、删除、插入等操作。
基本语法
sed [选项] '命令' 文件sed [选项] -f 脚本文件 文件
# 常用选项sed -n '10p' file.txt # 只显示第 10 行(-n 禁止默认输出)sed -i.bak 's/old/new/g' file.txt # 直接修改文件并备份sed -e 's/a/b/' -e 's/c/d/' file.txt # 执行多个命令替换操作(s 命令)
# 基本替换sed 's/foo/bar/' file.txt # 将每行第一个 foo 替换为 barsed 's/foo/bar/g' file.txt # 将每行所有 foo 替换为 bar
# 使用分隔符(避免转义)sed 's|/home/user|/home/newuser|' paths.txtsed 's@http://@https://@g' urls.txt
# 删除匹配内容sed 's/remove//g' file.txt
# 替换指定行sed '10s/old/new/' file.txt # 只替换第 10 行sed '/pattern/s/old/new/' file.txt # 只替换包含 pattern 的行
# 大小写转换sed 's/\(.*\)/\L\1/' file.txt # 转换为小写sed 's/\(.*\)/\U\1/' file.txt # 转换为大写删除操作(d 命令)
# 删除行sed '5d' file.txt # 删除第 5 行sed '/error/d' logfile.txt # 删除包含 error 的行sed '/^$/d' file.txt # 删除空行sed '5,10d' file.txt # 删除第 5-10 行sed '/start/,/end/d' file.txt # 删除从 start 到 end 的所有行sed '1d;$d' file.txt # 删除第一行和最后一行
# 删除注释行和空行sed '/^#/d;/^$/d' config.conf
# 删除行尾空白sed 's/[[:space:]]*$//' file.txt插入和追加操作(i、a、c 命令)
# 在指定行前插入sed '5i\# This is a new line' file.txt
# 在指定行后追加sed '5a\# This is an appended line' file.txt
# 在匹配行前插入sed '/pattern/i\# Header before pattern' file.txt
# 替换整行sed '5c\# This line replaces line 5' file.txt
# 文件头添加内容sed '1i\#!/bin/bash\n# Author: Admin' script.sh高级操作
# 多行处理sed 'N;s/\n/ /' file.txt # 合并连续两行sed '/pattern/{N;s/\n/ /;}' file.txt
# 持久空间和模式空间sed '/start/,/end/w output.txt' file.txt # 将匹配范围写入文件
# 条件处理sed '/error/{s/error/ERROR/;w error.log;}' logfile.txt
# 引用匹配内容(反向引用)sed 's/\([0-9]\{3\}\)\([0-9]\{4\}\)/\1-\2/' phone.txt# 将 1234567 转换为 123-4567
# 执行外部命令sed '10r /etc/hosts' file.txt # 在第 10 行后读取并插入文件内容实用示例
# 批量替换文件名中的空格为下划线for file in *; do mv "$file" "$(echo $file | sed 's/ /_/g')"; done
# 移除 HTML 标签sed 's/<[^>]*>//g' index.html
# 提取 IP 地址sed -n 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/p' access.log
# 格式化 JSON(简单美化)cat data.json | sed 's/{/{\n/g;s/}/}\n/g;s/,/,\n/g'
# 在每个函数定义前添加注释sed '/^def /i\# Function implementation' *.py
# 日志分析:提取错误信息sed -n '/ERROR/p' application.log | sed 's/^.*ERROR: /Error: /'
# 配置文件:启用选项sed -i 's/^#Port 22$/Port 22/' sshd_config
# CSV 处理:提取特定列sed 's/,[^,]*$//' data.csv # 删除最后一列awk:文本处理编程语言
awk 是一种强大的文本处理编程语言,特别擅长处理结构化文本(如 CSV、日志文件)。它以行为单位处理文本,自动将每行分割成字段,并提供了完整的编程语言特性。
基本结构
# 语法:awk 'pattern {action}' 文件awk '/pattern/ {print}' file.txt
# 默认行为:打印匹配的整行awk '/error/' logfile.txt
# 脚本格式awk 'BEGIN { # 初始化代码,执行一次}/pattern/ { # 对匹配行执行的代码}{ # 对每一行执行的代码}END { # 结束代码,执行一次}' file.txt字段处理
# 默认字段分隔符是空格和制表符awk '{print $1}' file.txt # 打印第一个字段awk '{print $1, $3}' file.txt # 打印第 1 和第 3 字段awk '{print $NF}' file.txt # 打印最后一个字段awk '{print $(NF-1)}' file.txt # 打印倒数第二个字段
# 指定字段分隔符awk -F: '{print $1}' /etc/passwd # 以冒号为分隔符awk -F, '{print $2}' data.csv # 以逗号为分隔符awk 'BEGIN {FS="|"} {print $1}' data.txt
# 输出字段分隔符awk 'BEGIN {FS=":"; OFS="-"} {print $1, $3}' /etc/passwd
# 记录分隔符awk 'BEGIN {RS=";"} {print $1}' data.txt内置变量
# 常用内置变量awk '{print NR, $0}' file.txt # NR:行号,$0:整行awk '{print FNR, $0}' file1.txt file2.txt # FNR:当前文件行号awk 'END {print NR}' file.txt # 总行数awk '{print NF}' file.txt # 每行字段数awk 'BEGIN {print FILENAME}' file.txt # 当前文件名
# 更多内置变量awk '{print $0}' file.txt # $0:整行内容awk '{if (NF > 5) print}' file.txt # NF:字段数量awk 'BEGIN {FS=":"; OFS="\t"}' file.txt # FS:输入分隔符,OFS:输出分隔符awk 'BEGIN {RS="\n\n"} {print}' file.txt # RS:记录分隔符awk 'BEGIN {ORS="\n\n"} {print}' file.txt # ORS:输出记录分隔符模式匹配
# 正则表达式匹配awk '/error/ {print}' logfile.txtawk '!/error/ {print}' logfile.txt # 不匹配awk '/^$/ {print NR}' file.txt # 空行的行号
# 字段匹配awk '$3 == "admin"' users.txtawk '$1 ~ /^[0-9]+$/' data.txt # 第一个字段是纯数字awk '$1 !~ /^#/ {print}' config.conf # 不以 # 开头
# 比较操作awk '$5 > 1000' sales.txt # 第 5 字段大于 1000awk '$1 == "John" && $2 == "Doe"' users.txtawk '$1 == "admin" || $1 == "root"' users.txt
# 范围模式awk '/start/,/end/' file.txt # 从 start 到 end 的所有行awk 'NR==10,NR==20' file.txt # 第 10-20 行控制结构
# if 语句awk '{if ($1 > 100) print "High:", $1; else print "Low:", $1}' data.txt
# for 循环awk '{for (i=1; i<=NF; i++) print $i}' file.txt
# while 循环awk '{i=1; while (i<=NF) {print $i; i++}}' file.txt
# 数组awk '{count[$1]++} END {for (name in count) print name, count[name]}' users.txt
# 函数awk 'function sum(arr) { total = 0 for (i in arr) total += arr[i] return total}{for (i=1; i<=NF; i++) nums[i] = $i}END {print sum(nums)}' numbers.txtBEGIN 和 END 块
# 计算列的平均值awk 'BEGIN {sum=0; count=0}{sum += $1; count++}END {print "Average:", sum/count}' numbers.txt
# 统计文件信息awk 'BEGIN {print "File Statistics:"}END {print "Total lines:", NR; print "Total fields:", sum}' file.txt
# 格式化输出awk 'BEGIN {printf "%-20s %10s %10s\n", "Name", "Age", "Salary"}{printf "%-20s %10d %10.2f\n", $1, $2, $3}END {print "--- End of report ---"}' employees.txt实用示例
# 统计每种状态的出现次数awk '{count[$1]++} END {for (status in count) print status, count[status]}' status.log
# 计算日志中不同 IP 的访问次数awk '{ip[$1]++} END {for (i in ip) print i, ip[i]}' access.log | sort -k2 -rn
# 提取 CSV 文件的特定列awk -F, '{print $1, $3}' data.csv
# 计算数字列的总和awk '{sum += $1} END {print sum}' numbers.txt
# 找出文件中最长的行awk '{if (length($0) > max) {max = length($0); line = $0}} END {print line}' file.txt
# 日志分析:计算平均响应时间awk '/response_time/ {sum += $3; count++} END {print "Avg:", sum/count}' server.log
# 转换为大写awk '{print toupper($0)}' text.txt
# 去除重复行(类似 uniq)awk '!seen[$0]++' file.txt
# 条件格式化awk '{if ($3 > 90) printf "%s\t%s\tA\n", $1, $2; else if ($3 > 80) printf "%s\t%s\tB\n", $1, $2; else printf "%s\t%s\tC\n", $1, $2}' grades.txt
# 多文件处理awk '{print FILENAME, NR, $0}' file1.txt file2.txt
# 时间戳转换awk '{print strftime("%Y-%m-%d %H:%M:%S", $1)}' timestamps.txt三剑客组合使用
在实际工作中,grep、sed、awk 经常组合使用以完成复杂的文本处理任务:
# 查找并统计错误类型grep "ERROR" application.log | awk '{print $4}' | sort | uniq -c
# 提取特定字段并进行转换cat data.csv | grep "^2024" | awk -F, '{print $2}' | sed 's/,//g' | sort -n
# 日志分析管道tail -f application.log | grep "ERROR" | awk '{print $1, $NF}' | while read ip message; do echo "Error from $ip: $message"done
# 复杂数据提取curl -s https://api.example.com/data | grep -o '"name":"[^"]*"' | sed 's/"name":"//g' | sed 's/"//g'
# 配置文件处理cat nginx.conf | grep server_name | awk '{print $2}' | sed 's/;//g'
# 日志统计报告awk '/ERROR/{err++} /WARN/{warn++} /INFO/{info++} END {printf "Errors: %d\nWarnings: %d\nInfo: %d\n", err, warn, info}' app.log性能优化和最佳实践
# 对于大文件,使用 grep 而不是 awk 进行简单匹配grep "pattern" largefile.txt # 比 awk '/pattern/' 快
# 使用 head 和 head -n 进行预览head -100 largefile.txt | awk '{...}'
# 使用 -i 选项时,注意性能影响grep "pattern" file.txt # 比 grep -i 快
# 在 sed 中使用 -n 减少输出sed -n '10,20p' file.txt # 只输出需要的行
# 在 awk 中使用数组统计时,注意内存使用awk '{count[$1]++} END {...}' largefile.txt # 如果唯一键太多会占用大量内存
# 使用管道处理大文件cat hugefile.txt | grep "pattern" | awk '{...}' > output.txt总结
grep、sed、awk 三个工具各有专长:
- grep:快速搜索和过滤文本,擅长模式匹配
- sed:流式编辑,擅长批量修改、删除、插入操作
- awk:完整的编程语言,擅长结构化数据处理和复杂计算
掌握这三个工具不仅能提高工作效率,还能帮助理解 Unix 系统的设计哲学——“做好一件事”。在实际工作中,根据任务需求选择合适的工具,或者组合使用它们,可以大大简化文本处理工作。建议从简单的例子开始练习,逐步掌握更复杂的用法,最终能够熟练运用这三个工具解决实际问题。
grep,sed,awk详解
https://sgjki547.top/posts/grep-sed-awk/