grep与正则表达式

grep基础

基本语法

grep [选项] 模式 [文件...]
grep [选项] [-e 模式 | -f 模式文件] [文件...]

常用选项

选项说明
-i忽略大小写
-v反向匹配(显示不匹配的行)
-n显示行号
-c只显示匹配行数
-l只显示匹配的文件名
-L只显示不匹配的文件名
-w匹配整个单词
-x匹配整行
-o只显示匹配的部分
-r / -R递归搜索目录
-E使用扩展正则表达式
-F固定字符串匹配(不解释正则)
-P使用Perl正则表达式
-A n显示匹配行及后n行
-B n显示匹配行及前n行
-C n显示匹配行及前后各n行
--color高亮显示匹配内容

基本用法示例

# 基本搜索
grep "error" /var/log/syslog
 
# 忽略大小写
grep -i "error" logfile
 
# 显示行号
grep -n "pattern" file
 
# 递归搜索目录
grep -r "function" /path/to/project/
 
# 只显示匹配的文件名
grep -l "TODO" *.py
 
# 显示匹配行数
grep -c "error" logfile
 
# 反向匹配
grep -v "^#" config.conf           # 排除注释行
 
# 匹配整个单词
grep -w "cat" file                  # 不匹配category
 
# 只显示匹配部分
grep -o "[0-9]\+" file              # 只显示数字
 
# 上下文显示
grep -C 3 "error" logfile           # 显示匹配行及前后3行

正则表达式

基本正则表达式(BRE)

元字符说明
.匹配任意单个字符
*匹配前一个字符0次或多次
[abc]匹配a、b或c中的任意一个
[^abc]匹配除a、b、c外的任意字符
[a-z]匹配a到z范围内的字符
^行首
$行尾
\{n,m\}匹配前一个字符n到m次
\{n\}匹配前一个字符n次
\{n,\}匹配前一个字符至少n次
\(\)分组
\1 \2引用第1、2个分组

扩展正则表达式(ERE)

使用 grep -Eegrep

元字符说明
+匹配前一个字符1次或多次
?匹配前一个字符0次或1次
``
()分组
{n,m}匹配前一个字符n到m次

Perl正则表达式(PCRE)

使用 grep -P

元字符说明
\d数字 [0-9]
\D非数字
\s空白字符
\S非空白字符
\w单词字符 [a-zA-Z0-9_]
\W非单词字符
\b单词边界
\B非单词边界

常用正则模式

匹配IP地址

# 简单匹配
grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" file
 
# 更精确匹配
grep -P "(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]?)" file

匹配邮箱

grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" file

匹配URL

grep -E "https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}[/a-zA-Z0-9._?=&-]*" file

匹配日期

# YYYY-MM-DD
grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2}" file
 
# DD/MM/YYYY
grep -E "[0-9]{2}/[0-9]{2}/[0-9]{4}" file

匹配手机号

# 中国手机号
grep -E "1[3-9][0-9]{9}" file

匹配空行

grep "^$" file
grep -v "^$" file                   # 排除空行

匹配注释行

grep "^#" file                       # #开头的注释
grep "^[[:space:]]*#" file           # 允许前面有空格
grep -v "^#" file                    # 排除注释行

高级用法

多模式匹配

# 使用-e指定多个模式
grep -e "error" -e "warning" -e "fail" logfile
 
# 使用扩展正则的|
grep -E "error|warning|fail" logfile
 
# 从文件读取模式
grep -f patterns.txt file

排除文件和目录

# 排除特定文件
grep -r --exclude="*.log" "pattern" /path/
 
# 排除特定目录
grep -r --exclude-dir=".git" "pattern" /path/
 
# 排除多个
grep -r --exclude="*.log" --exclude="*.tmp" --exclude-dir=".git" "pattern" /path/

统计分析

# 统计各IP访问次数
grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" access.log | sort | uniq -c | sort -rn
 
# 统计HTTP状态码
grep -o "\" [0-9]\{3\} " access.log | grep -o "[0-9]\{3\}" | sort | uniq -c
 
# 统计匹配次数
grep -c "error" logfile

配合其他命令

# 管道过滤
ps aux | grep nginx
ps aux | grep "[n]ginx"              # 排除grep进程本身
 
# 查找文件内容并显示文件名
find . -name "*.py" -exec grep -l "import requests" {} \;
 
# 结合xargs
grep -rl "old_string" . | xargs sed -i 's/old_string/new_string/g'
 
# 统计代码行数(排除空行和注释)
grep -v "^#" file | grep -v "^$" | wc -l

grep变体

egrep

# 等同于 grep -E
egrep "pattern1|pattern2" file

fgrep

# 等同于 grep -F,不解释正则
fgrep "string" file

rgrep

# 等同于 grep -r
rgrep "pattern" /path/

zgrep

# 搜索压缩文件
zgrep "pattern" file.gz

性能优化

# 使用-F加速固定字符串搜索
grep -F "exact_string" large_file
 
# 使用--mmap(某些系统)
grep --mmap "pattern" large_file
 
# 限制匹配次数
grep -m 10 "pattern" file             # 找到10个匹配后停止
 
# 并行搜索(使用parallel)
find . -type f | parallel grep -H "pattern" {}

💡 grep技巧:

  • 使用 -F 加速固定字符串搜索
  • 使用 grep "[p]attern" 避免匹配grep进程
  • 复杂正则先用 --color 测试
  • 大文件考虑使用 ripgrep (rg) 替代

🔗 相关笔记: 04.02_sed与awk 02.06_Shell脚本 99.01_常用命令速查表



title: sed与awk文本处理 tags: [Linux, sed, awk, 文本处理] date: 2026-04-20

sed与awk文本处理

sed流编辑器

基本语法

sed [选项] '命令' 文件
sed [选项] -f 脚本文件 文件

常用选项

选项说明
-n抑制自动输出,只输出处理的行
-e指定多个编辑命令
-f从脚本文件读取命令
-i直接修改文件(慎用)
-i.bak修改前备份原文件
-r / -E使用扩展正则表达式

地址定界

# 行号
sed '3d' file                         # 删除第3行
sed '1,5d' file                       # 删除1-5行
sed '$d' file                         # 删除最后一行
 
# 步长
sed '1~2d' file                       # 删除奇数行(从第1行开始,步长2)
sed '2~2d' file                       # 删除偶数行
 
# 正则匹配
sed '/pattern/d' file                 # 删除匹配行
sed '/start/,/end/d' file             # 删除start到end之间的行
sed '/pattern/!d' file                # 删除不匹配的行

替换命令

# 基本替换
sed 's/old/new/' file                 # 替换每行第一个
sed 's/old/new/g' file                # 替换每行所有
sed 's/old/new/2' file                # 替换每行第2个
sed 's/old/new/gp' file               # 替换并打印修改的行
sed 's/old/new/gw output' file        # 替换并写入output
 
# 忽略大小写
sed 's/old/new/gi' file
 
# 使用分隔符
sed 's|/path/old|/path/new|g' file    # 使用|作为分隔符
sed 's#/old#/new#g' file              # 使用#作为分隔符
 
# 使用正则
sed -r 's/[0-9]+/NUMBER/g' file       # 数字替换为NUMBER
sed 's/\b[a-z]\+\b/WORD/g' file       # 单词替换
 
# 使用捕获组
sed -r 's/([a-z]+) ([0-9]+)/\2 \1/g' file  # 交换位置
 
# 直接修改文件
sed -i 's/old/new/g' file
sed -i.bak 's/old/new/g' file         # 修改前备份

删除命令

sed 'd' file                          # 删除所有行
sed '3d' file                         # 删除第3行
sed '/pattern/d' file                 # 删除匹配行
sed '/^$/d' file                      # 删除空行
sed '/^#/d' file                      # 删除注释行

插入和追加

# i - 在匹配行前插入
sed '3i\new line' file                # 在第3行前插入
sed '/pattern/i\new line' file        # 在匹配行前插入
 
# a - 在匹配行后追加
sed '3a\new line' file                # 在第3行后追加
sed '/pattern/a\new line' file        # 在匹配行后追加
 
# c - 替换整行
sed '3c\new line' file                # 替换第3行
sed '/pattern/c\new line' file        # 替换匹配行
 
# 多行插入
sed '3i\
line1\
line2\
line3' file

打印命令

sed -n '3p' file                      # 打印第3行
sed -n '1,5p' file                    # 打印1-5行
sed -n '/pattern/p' file              # 打印匹配行
sed -n '$p' file                      # 打印最后一行

多命令执行

# 使用-e
sed -e 's/old1/new1/g' -e 's/old2/new2/g' file
 
# 使用分号
sed 's/old1/new1/g; s/old2/new2/g' file
 
# 使用大括号分组
sed '/pattern/{s/old/new/g; d}' file

awk文本处理

基本语法

awk [选项] '模式 {动作}' 文件
awk [选项] -f 脚本文件 文件

常用选项

选项说明
-F指定字段分隔符
-v定义变量
-f从脚本文件读取

内置变量

变量说明
$0当前整行
$1 $2第1、2…个字段
$NF最后一个字段
NF字段数量
NR当前记录号(行号)
FNR当前文件的记录号
FILENAME当前文件名
FS字段分隔符(默认空格)
OFS输出字段分隔符
RS记录分隔符(默认换行)
ORS输出记录分隔符
RT记录终止符

基本用法

# 打印整行
awk '{print}' file
awk '{print $0}' file
 
# 打印特定字段
awk '{print $1}' file                 # 打印第1列
awk '{print $1, $3}' file             # 打印第1和第3列
awk '{print $NF}' file                # 打印最后一列
 
# 指定分隔符
awk -F: '{print $1}' /etc/passwd
awk -F, '{print $1, $2}' file.csv
 
# 打印行号
awk '{print NR, $0}' file
 
# 格式化输出
awk '{printf "%-10s %5d\n", $1, $2}' file

模式匹配

# 正则匹配
awk '/pattern/' file                  # 打印匹配行
awk '/pattern/ {print $1}' file       # 打印匹配行的第1列
awk '$1 ~ /pattern/' file             # 第1列匹配
awk '$1 !~ /pattern/' file            # 第1列不匹配
 
# 条件匹配
awk '$3 > 100' file                   # 第3列大于100
awk '$1 == "root"' /etc/passwd        # 第1列等于root
awk 'NR > 5' file                     # 第5行之后
 
# 组合条件
awk '$3 > 100 && $4 < 50' file
awk '$3 > 100 || $5 == "yes"' file
 
# 范围匹配
awk '/start/,/end/' file              # start到end之间的行
awk 'NR>=10 && NR<=20' file           # 第10-20行

BEGIN和END

# BEGIN - 处理前执行
awk 'BEGIN {print "Header"} {print} END {print "Footer"}' file
 
# 计算总和
awk '{sum += $1} END {print sum}' file
 
# 计算平均值
awk '{sum += $1; count++} END {print sum/count}' file
 
# 设置分隔符
awk 'BEGIN {FS=":"; OFS="-"} {print $1, $3}' /etc/passwd
 
# 打印行列数
awk 'END {print NR}' file             # 总行数
awk '{print NF}' file                 # 每行字段数

数组

# 统计出现次数
awk '{count[$1]++} END {for (key in count) print key, count[key]}' file
 
# 分组求和
awk '{sum[$1] += $2} END {for (key in sum) print key, sum[key]}' file
 
# 数组赋值和访问
awk '{
    arr[1] = "one"
    arr[2] = "two"
    print arr[1], arr[2]
}' file
 
# 删除数组元素
awk '{arr[$1]++} {delete arr["key"]} END {for (k in arr) print k}' file

流程控制

# if-else
awk '{if ($3 > 100) print $1, "large"; else print $1, "small"}' file
 
# for循环
awk '{for (i=1; i<=NF; i++) print $i}' file
 
# while循环
awk '{i=1; while (i<=NF) {print $i; i++}}' file
 
# for-in循环
awk '{count[$1]++} END {for (key in count) print key, count[key]}' file

内置函数

# 字符串函数
awk '{print length($0)}' file         # 字符串长度
awk '{print substr($1, 1, 3)}' file   # 子串
awk '{print toupper($1)}' file        # 转大写
awk '{print tolower($1)}' file        # 转小写
awk '{print index($0, "pattern")}' file  # 查找位置
awk '{print split($0, arr, ",")}' file   # 分割字符串
awk '{print gensub(/old/, "new", "g", $0)}' file  # 替换
 
# 数学函数
awk '{print int($1)}' file            # 取整
awk '{print sqrt($1)}' file           # 平方根
awk '{print log($1)}' file            # 自然对数
awk '{print exp($1)}' file            # e的幂
awk '{print sin($1)}' file            # 正弦
awk '{print cos($1)}' file            # 余弦
 
# 其他函数
awk '{print srand()}' file            # 设置随机种子
awk '{print rand()}' file             # 随机数
awk '{print system("date")}' file     # 执行系统命令

自定义函数

awk '
function max(a, b) {
    return a > b ? a : b
}
{
    print max($1, $2)
}' file
 
# 带局部变量的函数
awk '
function sum(arr, n,    i, total) {
    total = 0
    for (i = 1; i <= n; i++)
        total += arr[i]
    return total
}
{
    for (i = 1; i <= NF; i++) a[i] = $i
    print sum(a, NF)
}' file

实用案例

日志分析

# 统计访问最多的IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
 
# 统计HTTP状态码
awk '{print $9}' access.log | sort | uniq -c | sort -rn
 
# 统计访问最多的URL
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -10
 
# 统计每小时的访问量
awk '{print substr($4, 14, 2)}' access.log | sort | uniq -c
 
# 计算平均响应时间
awk '{sum += $NF; count++} END {print "avg:", sum/count}' access.log

CSV处理

# 提取CSV列
awk -F, '{print $1, $3}' data.csv
 
# 过滤CSV行
awk -F, '$3 > 100 {print $0}' data.csv
 
# CSV转TSV
awk -F, 'BEGIN {OFS="\t"} {$1=$1; print}' data.csv
 
# 添加列标题
awk -F, 'BEGIN {print "Name,Age,Score"} {print}' data.csv

文本格式化

# 删除空行
sed '/^$/d' file
awk 'NF' file
 
# 删除行首行尾空格
sed 's/^[ \t]*//; s/[ \t]*$//' file
awk '{$1=$1; print}' file
 
# 每行添加行号
awk '{print NR, $0}' file
sed = file | sed 'N;s/\n/ /'
 
# 合并相邻行
sed 'N;s/\n/ /' file
awk '{printf "%s ", $0} NR%2==0 {print ""}' file

💡 文本处理建议:

  • 简单替换用sed,复杂处理用awk
  • 大文件处理考虑使用mawk(更快)
  • 复杂任务考虑使用Python/Perl
  • 测试时先不加-i,确认结果后再修改文件

🔗 相关笔记: 04.01_grep与正则表达式 02.06_Shell脚本 99.01_常用命令速查表