grep、awk、sed,三剑客介绍

三剑客

grep sed awk
-----------------------------------------------------------------------------------------------------------------------------------------
grep :行级过滤器、过滤文本中指定的内容(行)

使用格式:
grep [OPTIONS] PATTERN [FILE...]

options: 选项
pattern: 模式匹配
file: 文件名
注意: 将文件内容逐行读入到内存,进行模式匹配,一旦匹配成功,则显示该行一整行内容;如果没有匹配成功,则该行从内存中退出

一·常用选项

1). -i : 忽略大小写
2). -v : 取反
3). -A : 向后多显示几行
4). -B : 向上多显示几行
5). -C : 上下各多显示几行
6). -n : 显示过滤出内容,在原文件中的行号
7). -q : 静默输出,不会显示过滤内容;不会影响状态结果
8). -c : 统计过滤出了多少行
9). -rl : 根据文件中内容,过滤文件路径
10). -R : 根据文件中内容,过滤文件路径(会显示过滤的文件内容所在的行)

二·grep命令执行的状态结果:

可以过滤出内容: $? 为 0
没有过滤到内容: $? 为 1
文件名不存在: $? 为 2

------------------------------------正则表达式-----------------------------------------

正则表达式: 利用特殊字符,去代表特定的含义

元字符:

. 代表任意单个字符

* 代表了前面一个字符,可以出现0次到n次
例: ab*c --> ac abc abbbc abbbbbc

.* .可以出现0次到n次,也就代表了任意多个字符
注意:.*在匹配时,处于贪婪模式;能更多匹配,则去进行更多匹配

[] 从括号中任选一个字符

[^] 括号中的^代表取反

^ 行首锚定、行首

$ 行尾锚定、行尾

^$ 空行

< 词首锚定、词首

> 词尾锚定、词尾

转义符,将特殊含义去除

{} 引用、跟*类似; {5}前面字符必须出现5次;{2,5} 前面字符可以出现2次-5次

? 代表了前面一个字符,可以出现0次或1次

+ 代表了前面一个字符,可以出现1次到n次

() 分组;1 2 做分组后项引用

1 引用前面定义的第一个分组
2 引用第二个分组

1 2 3
(www) (.baidu.) (com)

((www).baidu.) (com) 1 --> www.baidu. 2 --> .baidu. 3 --> com

[a-z]{3} 匹配三个连续的字符

([a-z])11 匹配三个相同的连续字符
@@@-------awk功能:awk -F "." '{print $3"."$2"."$1}' 文件名 > 目标文件

vim替换功能:

定界(定址) s/旧内容/新内容/修饰符

逐行操作,读取一行,先做定界,如果定界成功,则执行替换

例1:
%s/o/H/

%代表了定界,代表所有行
3s : 只替换第3行;只在第3行执行s替换动作
1,3s : 替换1到3行;在1到3行执行s替换动作

注意: 默认只替换每行第一次匹配成功的字符

%s/o/H/g g是修改符,代表全局替换

注意:在vim替换功能中,旧内容匹配,支持正则表达式

--------------------------------------- sed 流编辑器 ----------------------------------------------------

工作原理
将文件逐行读入到内存;先定界(定址);定界成功,则运行子命令;若没定界成功,则不运行子命令;无论是否定界成功,只要没有执行具有删除动作的子命令,则默认将该行打印
sed一般用于处理大文件。
语法:
sed [选项] “定界 子命令” 文件名

----------------------模式空间

1、常用的选项
-n:静默输出,关闭模式空间的输出,一般与p一起用
-e:允许进行多项编辑,也就是说对同一行做多次处理、也可以做多点编辑
-e '动作' -e '动作' 等价于 '动作1;动作2'
-f sed脚本 : 指定运行的sed脚本的
-r:允许使用扩展正则
-i:直接修改原文件
2、定界方式:

----单个数值定界:
sed '9p' pass.txt
9代表定界到第九行

----两个数值:
sed '1,4 p' pass.txt

定界1到4行

sed '$ p' pass.txt
sed '3,$ p' pass.txt

$代表最后一行

----单个正则表达式:

sed '{/正则表达式/ 子命令 }' 文件名

sed '{/^bin/ p }' pass.txt

----两个正则表达式:
sed '{/正则表达式1/,/正则表达式2/ 子命令 }' 文件名

表达式1代表起点:

表达式2代表终点:

*****注释: 第一次匹配到表达式1算作起点;第一次匹配到表达式2算作终点
如果能匹配到表达式1,但是无法匹配到表达式2,则从匹配到表达式1的行开始,一直到文件末尾,都算定界成功
如果表达式1没有匹配成功,则所有行都定界失败

续行: 3,+4
sed '{3,+4 p }' pass.txt

步长: 1~2

sed '1~2 p' pass.txt

定界后,可以跟多个子命令:

3{p;p;p} 定界到3行时,执行3次p的子命令
3p;5p 定界3行和5行,分别运行子命令

3、Command

常用的:d p s y q
其他的:a c i r w
h H g G 用于模式空间和保留空间之间的操作
1)d:删除
~# sed '5,$d' /etc/passwd 删除从第5行开始到最后一行的所有内容

2)p:打印
~# sed -n '3,5p' pass // 打印文件的3到5行

3)r 读取,读取外部一个文件
~# sed '/^root/r /etc/issue' /etc/passwd

4)w 写,会将匹配到的内容,保存到外部的一个文件中
~# sed '/root/w /tmp/douni' pass //将匹配到的行另存到文件中

5)a 追加 在匹配到的行的下一行插入内容
~# sed '/root/a hello root' pass

6)i 插入 在匹配行的上一行插入内容
~# sed '/daemon/i SO COOL' pass

7)c 修改 本行替换,将匹配到的行的内容替换成新内容
~# sed '/root/c ROOT' pass

8)y 转换的命令,对应替换(替换字符相等长度)
~# sed 'y/1234/ABCF/' pass

9)n next 处理匹配行的下一行,用的较少
~# sed -n '/root/p' pass

10)q 退出 不再向模式空间读入新行
~# sed '/^bin/q' /etc/passwd

11)s 查找替换
定址s/模式匹配(旧的内容)/新的内容/[修饰符]


----------------------------------- 保留空间

h:将模式空间的内容复制到保留空间 —— 覆盖模式
H:将模式空间的内容追加到保留空间 —— 追加模式
g:将保留空间的内容复制到模式空间 —— 覆盖模式
G:将保留空间的内容追加到模式空间 —— 追加模式

x:将模式空间的内容和保留空间的内容进行交换

交换第一行和第二行的内容
~# sed '1{h;d};2G' pass

公式:#sed '1{h;d};2{G;h;d};3G' pass

#sed '1{h;d};2,4{G;h;d};5G' a.txt


------------------------------------------ AWK ----------------------------------------------
功能:对文本数据进行汇总和处理,是一个报告的生成器,能够对数据进行排版;格式化输出

AWK工作过程:
将文件内容逐行读入到内存;根据输入分隔符自动切片;将每片内容赋给指定的变量;定界(定界条件);一旦定界成功,则运行处理动作;一旦定界失败,不运行处理动作。

默认输入输出分隔符:空白;多个连续的空白当做一个分隔符

#vim a.txt
hello from tom $0:一整行
$1 $2 $3
用法格式------------------------------------------------------------------------------------------------

语法 : awk 选项 ‘定界 {处理动作1,处理动作2...}’ 文件名[文件2...]

基本内容:

-----awk输出
(1)print --打印内容的,内容可以是文件中的内容,也可以跟文件内容毫无关系
:换行符(默认) : 制表符
例: #echo hello | awk '{print "welcome to our school"}' ------echo作用相当于提供一个行;print$0
#welcome to our school

例: #echo hello | awk '{print "welcome to our school"}'
#welcome to
#our school

(2)printf —— 可以格式化输出的,默认没有换行
%s:表示是字符串
%d:表示十进制数 (%d直接取整,不进行四舍五入)
%f: 表示浮点数,其实就是小数 float (%f进行四舍五入的)
%%:表示%本身;可以不传递值
%x:表示十六进制数
%o:表示八进制数
%c:表示字符

修饰符: N(数字) 表示显示宽度 %10s
- 表示左对齐,默认是右对齐 %-10s
%% 表示% %d %% -----> 99 %

对于浮点数: %5.2f : 其中5表示总的显示宽度(整数位+小数位),2表示小数位的位数

#awk -F ":" '{printf "hello %s and uid %d ",$1,$3}' pass.txt
#hello root and uid 0


------选项

-F:指定输入文件字段分隔符

例: 打印pass文件中的用户名和uid

# awk -F “:” '{print $1,$3}' pass
# awk -F “:” '{print $1"用户uid为"$3}' pass --指定输出分隔符(方式一)
laozhang 用户uid为 500

----同时指定多个分隔符(:和/都是分隔符)

# awk -F"[:/]" '{print $1,$10}' pass

-v:调用指定变量并赋值 (大多用在脚本中)

-v FS=":" 指定输入分隔符
#awk -v FS=":" '{print $1,$3}' pass.txt

-v OFS="-->" 指定输出分隔符

-v RS="," 指定行分隔符(以谁分隔行)

-v NF:当前行的字段数
打印文件每一行最后一个字段
#awk '{print $NF}' a.txt

---------扩展:awk脚本 文件内容为awk命令的 '' 里的内容
vim a.sh
#!/bin/awk -f
BEGIN {
FS=":"
}
$2~/tom/{
print "nihao"
}

------awk的变量

种类:内置变量、自定义的变量
1)内置变量(內建变量)
(1) $0 $1 $2 $3 ...
(2) 与记录相关的变量(记录就是行)
FS(field separator):输入字段分隔符,默认是空白
FS=":"
OFS(Output):输出字段分隔符
RS(record):记录的分隔符,即行的分隔符,输入行分隔
注意:在输入时,指定完分隔符后, 失效
ORS:输出记录分隔符
#awk -v FS=':' '{print $1}' /etc/passwd
(3)与数据相关的变量
NR(Number of Record):记录数,awk的处理的行的总数 NR在很多情况下可以看成行号
读第一行时,NR等于1
读第二行时,NR等于2
读第三行时,NR等于3
...

FNR:行号,不会叠加
NF(Number of Field):当前行的字段数
$NF:当前行的最后一个字段的值
$(NF-1):当前行的倒数第二个字段

2)自定义变量
命名:由字母、数字、下划线组成,不能以数字开头,不能使用关键字,最好见名知意
变量名区分大小写
变量可以先定义再使用,也可以直接使用
例: # echo hello | awk '{num=5;pass="douniwan";print num,pass}'
# 5 douniwan

例: # echo hello | awk '{num=5;num+=1;print num}'
# 6


特殊用法--------------------------------------------

AWK 选项 ‘BEGIN{动作1} 定址{动作2}END{动作3}’ 文件

BEGIN : BEGIN 动作,是在读取文件内容之前执行的;打印头文件,定义初始变量...;begin中动作只运行一遍;
begin可以不借助任何文件
END : 在读取文件内容之后运行;打印尾部文件,只打印结果...;end中动作只运行一遍;必须借助文件。
例:打印头文件
#awk -F ":" 'BEGIN{print “the first”} {print $3+num} END{print "the end for first"}' pass.txt
#the first
#the end for first

例: 打印最近登录用户中IP地址为192.168.0.2的有多少次
last | awk 'BEGIN {num=0} $3=="192.168.0.2" {num++} END {print num}'
*********
例: 统计文件中第二例是“tom”的有多少行
awk 'BEGIN {sum=0} $2=="tom" {sum++} END{print sum}' b.txt

例: 统计文件中第三列数值的和
awk -F ":" 'BEGIN {sum=0} {sum+=$3} END{print sum}' pass.txt

awk中的运算:--------------------------------------

算术运算:+ - * / % ** ---------通常处理动作
比较运算:> < == != ---------通常为了定界(定界中有)
逻辑运算: && || ! ---------通常为了定界(定界中有)
位运算 :<< >> & | ~

算术运算
例: #echo hello | awk '{print 2+3}'
#5
例: #awk -F ":" '{print $1,$3+2}' pass.txt
#root 2

例: #awk -F ":" '{print $1,($3+$4)/2}' pass.txt
#root 0

例: 打印0~100中含有7的行
方式一:seq 100 | awk '/.*7.*/ {print $0}'
方式二:seq 100 | awk '$1~/7/' {print $1}
例: 打印0~100中能被二整除的行
seq 100 | awk '$1%2==0 {print $0}'


定界---------------------------------------------

单个正则表达式

awk '/正则表达式1/ {处理动作} ' 文件名

#df -Th | awk '//$/ {print $6}'
#31%

匹配正则 ~ (不匹配正则 !~)

(可以匹配带特点的列)
匹配文件中每一行第二列含有tom的有多少行
#awk '$2~/tom/ {print $0}' a.txt

两个正则表达式

awk '/正则表达式1/,/正则表达式2/ {处理动作} ' 文件名

awk -F ":" '/^root/,/^sync/ {print $0}' pass.txt

比较运算

(借助切片变量)
awk -F ":" '$1="root" {print $0}' pass.txt

awk -F ":" '$3>5 {print $0}' pass.txt

awk -F ":" '$3>=500 && $1!="nfsnobody" && $1!="cacti" && $1!="nagios"{print $0}' /etc/passwd

(借助NR变量)
awk -F ":" 'NR==5 {print $0}' pass.txt

特殊:awk -F ":" 'NR==3 || NR==5 {print $0}' pass.txt

逻辑运算

awk -F ":" '$3>=500 && $1!="nfsnobody" && $1!="cacti" && $1!="nagios"{print $0}' /etc/passwd

特殊:awk -F ":" 'NR==3 || NR==5 {print $0}' pass.txt

awk -F ":" 'NR>3 && NR<5 {print $0}' a.txt


awk中流程控制语句

1·awk与重定向

将uid>500的用户名及uid保存到/laozhang/pass.txt文件中

#awk -F ":" '$3>500 {print $1,$3 > "/laozhang/pass.txt"}' /etc/passwd

-------输入重定向 getline

getline 接收来自于标准输入、管道和文件(非当前处理文件)的数据,存入到一个变量中,再给awk使用

# awk -F ":" '$3>500 {print $1,$3 > "/laozhang/pass.txt"}' /etc/passwd

从标准输入读取一个数据,传给变量username,判断passwd文件中是否有这样的用户名,如果有,打印行号和用户名

# awk -F":" 'BEGIN {getline name < "/dev/pts/1"}{if($1==name){print NR,$1}}' a.txt

通过管道将命令结果传递给一个变量

#awk 'BEGIN {"date" | getline abc} {print $0} END {print abc}' a.txt
(文件结尾打印进入a.txt文件的系统时间)

基本结构
1、顺序结构
2、分支判断 if
3、循环结构 while for 循环控制语句:break continue exit next

一、三元操作符

如果条件为真,输出问号后面的结果,否则输出冒号后面的结果

# awk -F: '{print $1":"($3>$4?"uid"$3:"gid"$4)}' pass
(打印pass文件中每行的第三列和第四列最大的值)

二、if语句

格式:awk 选项 '定界 {if(条件){动作1} else if (条件){动作2} ... else {动作n}}' 文件列

例:**********
if双分支:
打印文件中uid大于等于500的用户为普通用户;小于500为系统用户
#awk -F ":" ' { if($3>=500){printf "%-10s 是普通用户 ",$1} else{printf "%-10s 是系统用户 ",$1} }' /etc/passwd

if多分支:
从终端读取变量值;对值进行判断
echo haha | awk 'BEGIN{getline abc < "/dev/pts/0"} {if(abc>=90){print "优秀"} else if (abc>=80){print "良好"}else if(abc>=60){print "及格"}else {print "不及格"}}'

三、循环
功能:
1)从行中取出每个字段,循环字段的 while
2)遍历数组元素 for

while语句:

格式:awk 选项 '定界 {定义初始变量;while(条件){动作;循环变量更新}}' 文件

例:
判断每行每片字符长度大于6的打印出来
#awk -F ":" '{i=1;while (i<=NF) {if(length($i)>6){print $i};i++}}' pass.txt
********************
统计文件中每列中“sync”出现了多少次
#awk -F ":" '{i=1;while(i<=NF){if ($i=="sync"){sum++};i++}} END{print sum}' pass.txt

将文件内容的行,竖着打印出来
#cat pass1.txt
sync:loring:tom:lisi:100

#awk -F ":" '{i=1;while ($i<=NF){print $i};i++}' pass1.txt
sync
loring
tom
lisi
100

for语句:

格式:awk 选项 '定界 {for(变量列表) {动作}}'

打印1~5
#awk 'BEGIN {for(i=1;i<=5);i++) {print $i}}'

用for语句实现
统计文件中每列中“sync”出现了多少次
#awk -F ":" '{for(i=1;i<=NF;i++) {if($i=="sync"){sum++}}} END{print sum}' a.txt

awk打印99乘法表
#awk 'BEGIN{for (i=1;i<=9;i++){for(j=1;j<=i;j++){printf "%d*%d=%d ",i,j,i*j};print " "}}'



----------- 数组 ------------

数组----内存中一段连续的地址空间(多个有序元素(值)的集合) 可理解为变量

数组中的术语:
数组元素 值
数组下标 跟元素对应的

数组下标:一般从0开始的 ---awk 中

name=(tom jerry laozhang laoli) 直接定义用空白分隔

靠下标引用元素 ${name[下标]}

echo ${name[0]} --> tom echo ${name[1]} --> jerry ........

数组遍历
echo ${name[*]} ---> tom jerry laozhang laoli

打印有元素个数
echo ${#name[*]} --> 4

引用最后一个元素值
echo ${name[${#name[*]}-1]} ---> laoli

数组元素支持单个修改;添加
name[2]=lisi


shell中下标:数值 -->0 1 2 3 4...
awk 中下标:数值 字符串
# vim b.txt
tom
jerry
tom
tom
jerry

打印文件第一列出现tom次数
# awk '$1=="tom"{sum['a']++} END{print sum['a']}' b.txt
# 3

打印文件中第一列不同的词出现的次数--------》》for(i in sum)为固定格式表示从sum数组元素中遍历值
# awk '{sum[$1]++} END{for(i in sum){print i,sum[i]}}' b.txt
# jerry 2
# tom 3

打印文件中所有 行;列 中 不同词出现的次数

# awk -F ":" '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/passwd
#netstat -ant

Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN
tcp 0 0 192.168.0.24:445 192.168.0.96:51437 ESTABLISHED
tcp 0 0 :::22 :::* LISTEN

统计每种连接状态各有多少人
# netstat -ant |awk '/tcp>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'

ESTABLISHED 4
LISTEN 21

统计第五段相同ip地址的访问次数
# netstat -ant | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i ,count[i]}}'

11
192.168.0.96 1
192.168.0.23 3
0.0.0.0 10

其中split($5,ip,":")----> split为awk内置函数将第五段再以冒号分隔切片 ; ip为数组名称且默认1为第一个下标(在awk中)
count[ip[1]]++ ------> ip[1]就为ip地址 count 再把IP地址当做下标 引用 相同自增。

awk '/UUID/{fs[$4]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab

awk 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";for(i in weekdays) {print weekdays[i]}}'

awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

awk -F ":" '{if($3%2!=0) next;print $1,$3}' /etc/passwd

原文地址:https://www.cnblogs.com/zhangshan-log/p/13745318.html