文本处理三剑客
文本处理三剑客
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 { 结束动作 }
模式类型
- 正则表达式:
/regex/
- 关系表达式:
$1 > 100
- 模式匹配:
$1 ~ /regex/
- 范围模式:
模式1, 模式2
- 特殊模式:
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
进行授权