文本处理三剑客
包括awk、sed和grep三种文本处理工具。
一、grep
grep命令:通过正则表达式查找文件中的关键字
1. 语法格式
- grep [option] [pattern] [file1,file2]
- command | grep [option] [pattern]
2. 选项
| 选项 | 含义 | 
| -v | 不显示匹配行信息 | 
| -i | 搜索时忽略大小写 | 
| -n | 显示行号 | 
| -r | 递归搜索 | 
| -E | 支持扩展正则表达式 | 
| -F | 不按正则表达式匹配,按照字符串字面意思匹配 | 
| -c | 只显示匹配行数 | 
| -w | 匹配整词 | 
| -x | 匹配整行 | 
| -l | 只显示文件名,不显示内容 | 
| -s | 不显示错误信息 | 
| -A <N> | 显示所找的匹配字段,并显示下面指定的行数的信息 | 
| -B <N> | 显示所找的匹配字段,并显示上面指定的行数的信息 | 
| -C <N> | 打印出匹配的上下文(上N行,下N行)前后的N行 | 
二、sed
sed命令:字符流编辑工具,对标准输出或文件逐行进行处理。
sed的两个临时缓冲区(空间):
- 模式空间:保存当前被处理的行
- 保持空间
1.功能
- 对行进行操作处理
- 对文件内容信息进行修改,删除、添加、查询
2.语法格式
- sed [OPTION] "pattern command" file
- command | sed [OPTION] "pattern command"
3.工作模式
- sed 一次处理一行文件的文本并将当前处理的行存储在临时缓冲区中(此又被称为模式空间“ pattern space”)
- Sed 一旦完成对模式空间中的行的处理,行将从空间中输出到屏幕。
- sed 在继续读入下一行,在如此继续,直至全部执行完成
4.选项
| 选项 | 含义 | 
| -n | 只打印模式匹配行,默认输出 | 
| -e | 允许多点编辑 | 
| -f | 编辑动作保存在文件中,指定文件执行 | 
| -r | 支持扩展正则表达式 | 
| -i | 直接修改文件内容 | 
5.pattern用法
| 匹配模式 | 含义 | 
| 10command | 匹配第10行 | 
| 10,20command | 从10行开始匹配到20行结束 | 
| 10,+5command | 从10行开始匹配,到15行结束 | 
| /pattern/command | 匹配有pattern的行,pattern可以是字符串或正则表达式 | 
| /pattern1/,/pattern2/command | 匹配到pattern1的行开始,到匹配到pattern2的行结束 | 
| 10,/pattern/command | 从10行开始,到匹配到pattern的行结束 | 
| /pattern/,10command | 从匹配到pattern的行开始,到第10行结束 | 
6.sed命令
命令语法:
- [address]command
- [address]{command1;command2}
6.1 基础命令
6.1 替换(s)
|  | root@gp:~# sed -i 's/UNIX/unix/g' file
 | 
常用的定界符#、@、/
6.2 删除(d)
如果匹配会删除整行
|  | # 删除空行
root@gp:~# sed -i '/^$/d' file  
 | 
6.3 追加(a)
在匹配行后添加
6.4 插入(i)
在匹配行前添加
6.5 更改(c)
删除匹配的行并替换为指定内容
|  | root@gp:~# sed  '/hello/c \HELLO WORLD' file
HELLO WORLD
 | 
6.5 列表(l)
显示模式空间的内容,可以显示非打印字符,如制表符等
|  | root@gp:~# sed  -n 'l' file
hello$
\tworld$
 | 
6.6 打印(p)
输出模式空间的内容。
|  | root@gp:~# sed  -n '$p' /etc/passwd
 | 
6.7 打印行号(=)
打印被匹配的行的行号
6.8 下一步(n)
小写n命令会告诉sed编辑器移动到数据流的下一行文本,而不用重新回到命令最开始再执行一遍。通常sed编辑器在移动到数据流中的下一行文本之前,会在当前行上执行完所有定义好的目命令。
|  | $ sed -i "/baidu/{n;/baidu/d}" hosts
 | 
6.9 读(r)
将一个文件的内容插入到指定位置
6.9 写(w)
将模式空间的内容写到文件中
6.10 退出(q)
使sed停止读取新的输入行
|  | # 输出前5行
root@gp:~# sed '5q' /etc/passwd
 | 
6.2 高级命令
高级命令改变了执行或控制的流程顺序。
6.2.1 多行Next(N)
读取新的输入行,并将它添加到模式空间的现有内容之后。
例1:
|  | root@gp:~# cat file
This is the header line.
This is the first line.
This is the second line.
This is the last line.
# 将两行合并为一行
root@gp:~# sed '/first/{N; s/\n/ /}' file
This is the header line.
This is the first line. This is the second line.
This is the last line.
 | 
例2:
|  | root@gp:~# cat file.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrator should attent.
Thank you for your attend.
# 替换分散在两行中的文本短语
root@gp:~# sed 's/System Administrator/Desktop User/;N;s/System\nAdministrator/Desktop\nUser/' file.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop User should attent.
Thank you for your attend.
 | 
6.2.2 多行删除(D)
只删除模式4空间的第一行。该命令会删除到换行符为止的所有字符。
D命令会强制sed编辑器返回到脚本的起始处,对模式空间中的内容重新执行这些命令(不会从数据流中读取新的文本行)
例1:删除匹配行的前一行文本
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14 | root@gp:~# cat file
This is the header line.
This is the first line.
This is the second line.
This is the last line.
# 删除匹配行的前一行文本
root@gp:~# sed '/^$/{N;/header/D}' file
This is the header line.
This is the first line.
This is the second line.
This is the last line.
 | 
例2:将多个空行合并为一个空行
|  | root@gp:~# sed '/^$/{N;/^\n$/D}' file
 | 
6.2.3 多行打印(P)
输出多行模式空间的第一部分,直到第一个换行符为止。这个命令经常出现在Next之后和Delete之前。
6.3 保持空间
用途: 在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。
| 命令 | 描述 | 
| h | 将模式空间复制到保持空间 | 
| H | 将模式空间追加到保持空间 | 
| g | 将保持空间复制到模式空间 | 
| G | 将保持空间追加到模式空间 | 
| x | 交换模式空间和保持空间的内容 | 
6.4 流程控制
1. 分支(b)
在脚本中将控制权转移到另一行
[address]b[label]
address:决定哪些行的数据会触发分支命令
label:定义要跳转到的位置,如果没有label,就跳转到脚本的结尾
例1:不加标签
|  | root@gp:~# cat file
This is the header line.
This is the first line.
This is the second line.
This is the last line.
# 跳过第2,3行
root@gp:~# sed '{2,3b; s/This is/Is this/; s/line./test?/}' file
Is this the header test?
This is the first line.
This is the second line.
Is this the last test?
 | 
例2:使用标签
| 编辑命令 | 含义 | 
| p | 打印 | 
| a | 行后追加 | 
| i | 行前追加 | 
| r | 外部文件读取,行后追加 | 
| w | 匹配行写入外部文件 | 
| d | 删除 | 
| s/old/new/ | 将行内的第一个old替换为new | 
| s/old/new/g | 将行内全部的old替换为new | 
| s/old/new/2g | 同一行内,只替换从第2个开始到剩下所有符合条件的 | 
| s/old/new/ig | 将行内全部的old替换为new,忽略大小写 | 
| = | 显示匹配的行号,但是不显示内容 | 
7.反向引用
| 字符 | 功能 | 
| & | 保存所搜索字符用来替换其他字符 | 
| () | 分组,把需要引用的部分括起来 | 
7.1. 使用&引用
|  | $ sed -n 's/ubuntu/++&++/p' passwd
++ubuntu++:x:1000:1000:ubuntu,,,:/home/ubuntu:/bin/bash
 | 
7.2. 使用()分组引用
|  | $ sed -n 's/\(ro\)../\1OT/gp' passwd
roOT:x:0:0:roOT:/roOT:/bin/bash
 | 
8.变量引用
匹配模式中使用变量时,使用双引号,否则需要把变量用单引号括起来
"s/$old/$new/g" 或 's/'$old'/'$new'/g'
三、awk
awk:报告生成器,是 Alfred Aho,Peter Weinberger,Brian Kernighan 三位作者联合开发的。
1.语法格式
- awk 'BEGIN{}pattern{commmand}END{}' file
- command | awk 'BEGIN{}pattern{commmand}END{}'
| 语法格式 | 含义 | 
| BEGIN{} | 正式处理数据之前执行 | 
| pattern | 匹配模式 | 
| {commands} | 处理命令,可以多行 | 
| END{} | 处理完所有匹配数据后的执行 | 
2.内置变量
| 内置变量 | 含义 | 
| $0 | 整行内容 | 
| $ | 当前行的第n个字段 | 
| NF | Number Field,当前行的字段个数,也就是有多少列 | 
| NR | Number Row,当前行的行号,从1开始计数 | 
| FNR | File Number Row多文件处理是,每个文件行号单独计数,都是从1开始 | 
| FS | Field Separator,输入字段分割符,默认以空格或tab分割 | 
| RS | Row Separator,输入行分隔符,默认回车换行 | 
| OFS | Output Field Separator,输出字段分隔符,默认空格 | 
| ORS | Output Row Separator,输出行分隔符,默认回车换行 | 
| FILENAME | 当前输入的文件名称 | 
| ARGC | 命令行参数个数 | 
| ARGV | 命令行参数数组 | 
3. 输出
3.1. printf
| 格式符 | 含义 | 
| %s | 打印字符串 | 
| %d | 打印十进制数 | 
| %f | 打印浮点数 | 
| %x | 打印十六进制数 | 
| %o | 打印八进制数 | 
| %e | 打印数字的科学技术法格式 | 
| %c | 打印单个字符的ASCII | 
| 修饰符 | 含义 | 
| - | 左对齐 | 
| + | 右对齐 | 
| # | 显示8进制在前面加0,显示16进制在前面加0x | 
|  | # printf
$ awk 'BEGIN{FS=":"}{printf "%-20s %10s\n",$1,$7}' /etc/passwd
 | 
3.2 print
|  | $ awk 'BEGIN{FS=":"}/root/{printf $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
 | 
4.匹配模式
4.1.正则表达式匹配
|  | $ awk 'BEGIN{FS=":"}/root/{printf $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
 | 
4.2.关系运算匹配
| 关系运算符 | 含义 | 
| < | 小于 | 
| <= | 小于等于 | 
| > | 大于 | 
| >= | 大于等于 | 
| == | 等于 | 
| != | 不等于 | 
| ~ | 匹配正则表达式 | 
| !~ | 不匹配正则表达式 | 
|  | # 关系运算符匹配
$ awk -F ":" '$3>=1000 {print $0}' /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
ubuntu:x:1000:1000:ubuntu,,,:/home/ubuntu:/bin/bash
 | 
|  | # 正则匹配
$ awk -F ":" '$1~/root/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
 | 
4.3. 布尔运算符匹配
|  | # 布尔运算符匹配
$ awk -F ":" '$3==0 || $3>=1000 {printf "%s\n",$0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
ubuntu:x:1000:1000:ubuntu,,,:/home/ubuntu:/bin/bash
 | 
5. 表达式
5.1. 算数运算符
| 运算符 | 含义 | 
| + | 加 | 
| - | 减 | 
| * | 乘 | 
| / | 除 | 
| % | 取模 | 
| ^或** | 乘方 | 
| ++x | 在返回x变量之前,x变量加1 | 
| x++ | 在返回x变量之后,x变量加1 | 
|  | # 算数运算
$ awk 'BEGIN{x=10;y=30;print x+y}'
40
 | 
|  | # 统计空行
$ awk '/^$/{cnt++}END{print cnt}' /etc/services
6
 | 
6. 逻辑控制
语法格式同C语言。
6.1. if
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | $ awk -F ":"  '{if ($3==0) {printf "%-10s%s\n","root用户:",$1} else {printf "%-10s%s\n","普通用户:",$1}}' /etc/passwd
root用户:   root
普通用户:     daemon
普通用户:     bin
普通用户:     sys
普通用户:     sync
普通用户:     games
普通用户:     man
普通用户:     lp
普通用户:     mail
普通用户:     news
普通用户:     uucp
普通用户:     proxy
普通用户:     www-data
普通用户:     backup
普通用户:     list
普通用户:     irc
普通用户:     gnats
普通用户:     nobody
普通用户:     systemd-timesync
普通用户:     systemd-network
普通用户:     systemd-resolve
普通用户:     systemd-bus-proxy
普通用户:     syslog
普通用户:     _apt
普通用户:     lxd
普通用户:     messagebus
普通用户:     uuidd
普通用户:     dnsmasq
普通用户:     sshd
普通用户:     ubuntu
 | 
6.2. do...while
|  | $ awk 'BEGIN{do{sum+=i;i++}while(i<=100) print sum}'
5050
 | 
6.3. while
|  | $ awk 'BEGIN{while(i<=100){sum+=i;i++}print sum}'
5050
 | 
6.4. for
7. 字符串函数
| 函数名 | 解释 | 返回值 | 
| length(str) | 计算字符串长度 | 整数长度值 | 
| index(str1,str2) | 在str1中查找str2的位置 | 返回值为位置索引,从1计数 | 
| tolower(str) | 转换为小写 | 转换后的小写字符串 | 
| toupper(str) | 转换为大写 | 转换后的大写字符串 | 
| substr(str,m,n) | 从str的m个字符开始,截取n位 | 截取后的子串 | 
| split(str,arr,fs) | 按fs分割字符串,结果保存arr | 切割后的子串个数 | 
| match(str,RE) | 在str中按照RE查找,返回位置 | 返回索引位置 | 
| sub(RE,RepStr,str) | 在str中搜索符合RE的字串,将其替换为RepStr,只替换第一个 | 替换的个数 | 
| gsub(RE,RepStr,str) | 在str中搜索符合RE的字串,将其替换为RepStr,替换所有 | 替换的个数 | 
8. 选项
| 选项 | 解释 | 
| -v | 定义或引用变量 | 
| -f | 指定脚本文件 | 
| -F | 指定分隔符 | 
| -V | 查看版本号 | 
|  | # 把外部变量引入awk
$ x=12
$ awk -v y="$x" 'BEGIN{print y}'
12
 |