文章

文本处理三剑客

文本处理三剑客

grep/sed/awk 使用笔记

grep 语法结构

基本语法

1
grep [选项] 模式 [文件...]

选项结构

  • -i:忽略大小写
  • -v:反向匹配(显示不匹配的行)
  • -n:显示行号
  • -c:计数匹配行数
  • -l:只显示文件名
  • -w:全词匹配
  • -A num:显示匹配行及后面num行
  • -B num:显示匹配行及前面num行
  • -C num:显示匹配行及前后各num行

模式语法

  • 普通字符:直接匹配
  • .:匹配任意单个字符
  • ^:匹配行首
  • $:匹配行尾
  • [ ]:字符集匹配
  • [^ ]:否定字符集
  • *:前导字符出现0次或多次
  • \+:前导字符出现1次或多次(需用-E)
  • \?:前导字符出现0次或1次(需用-E)
  • \{n,m\}:前导字符出现n到m次

sed 语法结构

基本语法

1
sed [选项] '命令' [输入文件...]

常用选项

  • -n:禁止自动打印模式空间
  • -e:指定多个编辑命令
  • -i:直接修改文件
  • -f:从文件读取sed脚本

命令结构

1
[地址范围] 命令 [参数]

地址范围

  • n:第n行
  • n,m:从n到m行
  • n,+k:从n行开始的k行
  • /pattern/:匹配模式的行
  • $:最后一行

常用命令

  • s/正则/替换/[标志]:替换
    • 标志:g(全局), p(打印), i(忽略大小写)
  • d:删除
  • p:打印
  • a\文本:在指定行后追加
  • i\文本:在指定行前插入
  • c\文本:替换整行
  • y/源字符集/目标字符集/:字符转换

awk 语法结构

基本语法

1
awk [选项] '模式 {动作}' [输入文件...]

常用选项

  • -F fs:设置字段分隔符
  • -v var=value:定义变量
  • -f scriptfile:从文件读取awk脚本

程序结构

1
2
3
BEGIN { 初始化动作 }
模式 { 处理动作 }
END { 结束动作 }

模式类型

  1. 正则表达式:/regex/
  2. 关系表达式:$1 > 100
  3. 模式匹配:$1 ~ /regex/
  4. 范围模式:模式1, 模式2
  5. 特殊模式:
    • BEGIN:处理前执行
    • END:处理后执行

动作结构

  • 表达式:变量 = 表达式
  • 控制语句:
    1
    2
    3
    4
    
    if (条件) 动作 [else 动作]
    while (条件) 动作
    for (表达式; 条件; 表达式) 动作
    for (变量 in 数组) 动作
    
  • 输入输出:
    1
    2
    3
    
    print [表达式列表]
    printf 格式 [, 表达式列表]
    getline
    

内置变量

  • FS:输入字段分隔符
  • OFS:输出字段分隔符
  • RS:输入记录分隔符
  • ORS:输出记录分隔符
  • NF:当前记录字段数
  • NR:当前记录数
  • FNR:当前文件记录数
  • FILENAME:当前文件名

操作符

  • 算术:+ - * / % ^
  • 赋值:= += -= *= /= %= ^=
  • 比较:== != < > <= >=
  • 逻辑:&& || !
  • 正则:~ !~
  • 条件:?:
  • 连接:(无操作符,直接连接)

控制流示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    if ($1 > 50) {
        print "Large:", $0
    } else if ($1 > 20) {
        print "Medium:", $0
    } else {
        print "Small:", $0
    }
    
    for (i = 1; i <= NF; i++) {
        sum += $i
    }
    
    while (count < 10) {
        print count
        count++
    }
}

函数

内置函数

  • 数学:sin(), cos(), sqrt(), int(), rand()
  • 字符串:length(), substr(), index(), split(), gsub()
  • 时间:systime(), strftime()
  • 位操作:and(), or(), xor()

自定义函数

1
2
3
4
function 函数名(参数列表) {
    函数体
    return 返回值
}

grep 命令

grep [选项] 模式 [文件…]

基本用法

1
2
3
4
5
6
7
8
9
10
11
grep "pattern" file.txt          # 在文件中搜索匹配模式的行
grep -i "pattern" file.txt       # 忽略大小写
grep -v "pattern" file.txt       # 反转匹配,显示不匹配的行
grep -n "pattern" file.txt       # 显示匹配行的行号
grep -c "pattern" file.txt       # 统计匹配行的数量
grep -r "pattern" /path/to/dir   # 递归搜索目录中的文件
grep -l "pattern" *.txt          # 只显示包含匹配项的文件名
grep -w "word" file.txt          # 全词匹配
grep -A 3 "pattern" file.txt     # 显示匹配行及其后3行
grep -B 2 "pattern" file.txt     # 显示匹配行及其前2行
grep -C 1 "pattern" file.txt     # 显示匹配行及其前后各1行

正则表达式

1
2
3
4
5
6
7
8
9
grep "^start" file.txt          # 以"start"开头的行
grep "end$" file.txt            # 以"end"结尾的行
grep "a..b" file.txt            # a和b之间有两个任意字符
grep "[a-z]" file.txt           # 包含任意小写字母
grep "[^0-9]" file.txt          # 包含非数字字符
grep "a*b" file.txt             # a出现0次或多次后跟b
grep "a\+b" file.txt            # a出现1次或多次后跟b (需加-E或使用egrep)
grep -E "a{2,4}b" file.txt      # a出现2到4次后跟b
grep "a\|b" file.txt            # 匹配a或b (需加-E或使用egrep)

sed 命令

sed [选项] ‘命令’ [输入文件…]

基本用法

1
2
3
4
5
6
7
8
9
10
11
sed 's/old/new/' file.txt        # 替换每行第一个匹配的old为new
sed 's/old/new/g' file.txt       # 替换所有匹配的old为new
sed 's/old/new/2' file.txt       # 替换每行第二个匹配的old为new
sed -n '3p' file.txt             # 只打印第3行
sed -n '1,5p' file.txt           # 打印1到5行
sed -n '/pattern/p' file.txt     # 打印匹配pattern的行
sed '/pattern/d' file.txt        # 删除匹配pattern的行
sed '3d' file.txt                # 删除第3行
sed '1,5d' file.txt              # 删除1到5行
sed -i '' 's/old/new/' file.txt  # 直接修改文件(BSD/macOS)
sed -i 's/old/new/' file.txt     # 直接修改文件(Linux)

高级用法

1
2
3
4
5
6
7
8
sed 's/^/# /' file.txt           # 在每行开头添加注释符号
sed '/pattern/a\new line' file.txt # 在匹配行后追加一行
sed '/pattern/i\new line' file.txt # 在匹配行前插入一行
sed 'y/abc/ABC/' file.txt        # 字符转换,a->A, b->B, c->C
sed -n '1~2p' file.txt           # 打印奇数行
sed -n '2~2p' file.txt           # 打印偶数行
sed '=' file.txt | sed 'N;s/\n/\t/' # 显示行号
sed -e 's/foo/bar/' -e 's/baz/qux/' file.txt # 多个编辑命令

awk 命令

awk [选项] ‘模式 {动作}’ [输入文件…]

基本用法

1
2
3
4
5
6
7
awk '{print $1}' file.txt        # 打印每行的第一个字段
awk '{print $NF}' file.txt       # 打印每行的最后一个字段
awk '{print NR, $0}' file.txt    # 打印行号和整行内容
awk 'NR==3' file.txt             # 打印第3行
awk 'NR>=3 && NR<=5' file.txt    # 打印3到5行
awk '/pattern/' file.txt         # 打印匹配pattern的行
awk 'length($0) > 80' file.txt   # 打印长度大于80个字符的行

内置变量

1
2
3
4
5
6
7
NR - 当前记录数(行号)
NF - 当前记录的字段数
FS - 输入字段分隔符(默认是空格)
OFS - 输出字段分隔符(默认是空格)
RS - 输入记录分隔符(默认是换行符)
ORS - 输出记录分隔符(默认是换行符)
FILENAME - 当前文件名

高级用法

1
2
3
4
5
6
7
awk -F: '{print $1}' /etc/passwd  # 指定分隔符为冒号
awk '{sum += $1} END {print sum}' file.txt # 计算第一列的总和
awk 'BEGIN {FS=":"; OFS="\t"} {print $1,$3}' /etc/passwd # 设置输入输出分隔符
awk '$3 > 100 {print $0}' file.txt # 打印第三列大于100的行
awk '{if ($1 > 50) print $1; else print "Nope"}' file.txt # 条件判断
awk 'BEGIN {for(i=1;i<=5;i++) print i}' # 循环打印1到5
awk '{a[$1]++} END {for(i in a) print i, a[i]}' file.txt # 统计第一列出现次数

组合使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 查找包含"error"的行并提取时间戳
grep "error" log.txt | awk '{print $1, $2}'

# 统计文件中各单词出现频率
sed 's/[^a-zA-Z]/ /g' file.txt | tr ' ' '\n' | grep -v '^$' | sort | uniq -c | sort -nr

# 替换文件中的日期格式从MM/DD/YYYY到YYYY-MM-DD
sed -E 's#([0-9]{2})/([0-9]{2})/([0-9]{4})#\3-\1-\2#g' dates.txt

# 提取CSV文件中第二列大于100的行
awk -F, '$2 > 100' data.csv

# 删除文件中的空行和注释行
sed '/^#/d;/^$/d' config.ini

# 计算目录中所有.txt文件的总行数
find . -name "*.txt" -exec wc -l {} + | awk '{sum += $1} END {print sum}'

# 提取nginx日志中状态码不是200的请求
awk '$9 != 200 {print $7, $9}' access.log
本文由作者按照 CC BY 4.0 进行授权