grep、sed、awk

目录

grep、sed、awk

grep

什么是grep和egrep

使用grep

命令格式

命令功能

命令参数

sed

认识sed

使用sed

命令格式

常用选项options

地址定界

编辑命令command

sed用法演示

常用选项options演示

地址界定演示

编辑命令command演示

sed高级编辑命令

awk

认识awk

使用awk

语法

常用命令选项

awk变量

内置变量

自定义变量

printf命令

格式

演示

操作符

格式

演示

awk PATTERN 匹配部分

格式

演示

awk有意思的案例

awk高阶用法

awk控制语句—if-else判断

awk控制语句—while循环

awk控制语句—do-while循环

awk控制语句—for循环

和shell脚本中较相似的控制语句

break和continue

next

awk数组

关联数组:array[index-expression]

演示

数值\字符串处理

awk自定义函数

awk中调用shell 命令

awk实战案例

统计TCP连接状态数量

统计日志中各IP访问非200状态码的次数


grep、sed、awk

grep

什么是grep和egrep

  Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配到的标红)。

  egrep = grep -E:扩展的正则表达式 (除了< , > , \b 使用其他正则都可以去掉\)

使用grep

命令格式
grep` `[option] pattern ``file
命令功能

用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。

命令参数

常用参数已加粗

  • -A<显示行数>:除了显示符合范本样式的那一列之外,并显示该行之后的内容。

  • -B<显示行数>:除了显示符合样式的那一行之外,并显示该行之前的内容。

  • -C<显示行数>:除了显示符合样式的那一行之外,并显示该行之前后的内容。

  • -c:统计匹配的行数

  • -e :实现多个选项间的逻辑or 关系

  • -E:扩展的正则表达式

  • -f FILE:从FILE获取PATTERN匹配

  • -F :相当于fgrep

  • -i --ignore-case #忽略字符大小写的差别。

  • -n:显示匹配的行号

  • -o:仅显示匹配到的字符串

  • -q: 静默模式,不输出任何信息

  • -s:不显示错误信息。

  • -v:显示不被pattern 匹配到的行,相当于[^] 反向匹配

  • -w :匹配 整个单词

sed

认识sed

  sed 是一种流编辑器,它一次处理一内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace ),接着用sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。如果没有使诸如‘D’ 的特殊命令,那会在两个循环之间清空模式空间,但不会清空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出或-i

  功能:主要用来自动编辑一个或多个文件, 简化对文件的反复操作

使用sed

命令格式
sed` `[options] ``'[地址定界] command'` `file``(s)
常用选项options
  • -n:不输出模式空间内容到屏幕,即不自动打印,只打印匹配到的行

  • -e:多点编辑,对每行处理时,可以有多个Script

  • -f:把Script写到文件当中,在执行sed时-f 指定文件路径,如果是多个Script,换行写

  • -r:支持扩展的正则表达式

  • -i:直接将处理的结果写入文件

  • -i.bak:在将处理的结果写入文件之前备份一份

地址定界
  • 不给地址:对全文进行处理

  • 单地址:

    • #: 指定的行

    • /pattern/:被此处模式所能够匹配到的每一行

  • 地址范围:

    • #,#

    • #,+#

    • /pat1/,/pat2/

    • #,/pat1/

  • ~:步进

    • sed -n '1~2p' 只打印奇数行 (1~2 从第1行,一次加2行)

    • sed -n '2~2p' 只打印偶数行

编辑命令command
  • d:删除模式空间匹配的行,并立即启用下一轮循环

  • p:打印当前模式空间内容,追加到默认输出之后

  • a:在指定行后面追加文本,支持使用\n实现多行追加

  • i:在行前面插入文本,支持使用\n实现多行追加

  • c替换行为单行或多行文本,支持使用\n实现多行追加

  • w:保存模式匹配的行至指定文件

  • r:读取指定文件的文本至模式空间中匹配到的行后

  • =:为模式空间中的行打印行号

  • !:模式空间中匹配行取反处理

  • s///

    查找替换

    ,支持使用其它分隔符,如:

    s@@@

    s###

    • 加g表示行内全局替换;

    • 在替换时,可以加一下命令,实现大小写转换

    • \l:把下个字符转换成小写。

    • \L:把replacement字母转换成小写,直到\U或\E出现。

    • \u:把下个字符转换成大写。

    • \U:把replacement字母转换成大写,直到\L或\E出现。

    • \E:停止以\L或\U开始的大小写转换

sed用法演示

常用选项options演示
[root@along ~]# cat demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed "/aaa/p" demo  #匹配到的行会打印一遍,不匹配的行也会打印
aaa
aaa
bbbb
AABBCCDD
[root@along ~]# sed -n "/aaa/p" demo  #-n不显示没匹配的行
aaa
[root@along ~]# sed -e "s/a/A/" -e "s/b/B/" demo  #-e多点编辑
Aaa
Bbbb
AABBCCDD
[root@along ~]# cat sedscript.txt
s/A/a/g
[root@along ~]# sed -f sedscript.txt demo  #-f使用文件处理
aaa
bbbb
aaBBCCDD
[root@along ~]# sed -i.bak "s/a/A/g" demo  #-i直接对文件进行处理
[root@along ~]# cat demo
AAA
bbbb
AABBCCDD
[root@along ~]# cat demo.bak
aaa
bbbb
AABBCCDD
地址界定演示
[root@along ~]# cat demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed -n "p" demo  #不指定行,打印全文
aaa
bbbb
AABBCCDD
[root@along ~]# sed "2s/b/B/g" demo  #替换第2行的b->B
aaa
BBBB
AABBCCDD
[root@along ~]# sed -n "1,2p" demo  #打印1-2行
aaa
bbbb
[root@along ~]# sed -n "/aaa/,/DD/p" demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed -n "2,/DD/p" demo
bbbb
AABBCCDD
[root@along ~]# sed "1~2s/[aA]/E/g" demo  #将奇数行的a或A替换为E
EEE
bbbb
EEBBCCDD
编辑命令command演示
[root@along ~]# cat demo
aaa
bbbb
AABBCCDD
[root@along ~]# sed "2d" demo  #删除第2行
aaa
AABBCCDD
[root@along ~]# sed -n "2p" demo  #打印第2行
bbbb
[root@along ~]# sed "2a123" demo  #在第2行后加123
aaa
bbbb
123
AABBCCDD
[root@along ~]# sed "1i123" demo  #在第1行前加123
123
aaa
bbbb
AABBCCDD
[root@along ~]# sed "3c123\n456" demo  #替换第3行内容
aaa
bbbb
123
456
[root@along ~]# sed -n "3w/root/demo3" demo  #保存第3行的内容到demo3文件中
[root@along ~]# cat demo3
AABBCCDD
[root@along ~]# sed "1r/root/demo3" demo  #读取demo3的内容到第1行后
aaa
AABBCCDD
bbbb
AABBCCDD
[root@along ~]# sed -n "=" demo  #=打印行号
1
2
3
[root@along ~]# sed -n '2!p' demo  #打印除了第2行的内容
aaa
AABBCCDD
[root@along ~]# sed 's@[a-z]@\u&@g' demo  #将全文的小写字母替换为大写字母
AAA
BBBB
AABBCCDD

sed高级编辑命令

(1)格式

  • h:把模式空间中的内容覆盖至保持空间中

  • H:把模式空间中的内容追加至保持空间中

  • g:从保持空间取出数据覆盖至模式空间

  • G:从保持空间取出内容追加至模式空间

  • x:把模式空间中的内容与保持空间中的内容进行互换

  • n:读取匹配到的行的下一行覆盖 至模式空间

  • N:读取匹配到的行的下一行追加 至模式空间

  • d:删除模式空间中的行

  • D:删除 当前模式空间开端至\n 的内容(不再传 至标准输出),放弃之后的命令,但是对剩余模式空间重新执行sed 

(2)一个案例+示意图演示

① 案例:倒序输出文本内容

[root@along ~]# cat num.txt
One
Two
Three
[root@along ~]# sed '1!G;h;$!d' num.txt
Three
Two
One
​
1!G 第一行不执行G命令,从第二行开始执行
​
$!d 最后一行不删除

awk

认识awk

  awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。

使用awk

语法
awk` `[options] ``'program'` `var=value ``file``…``awk` `[options] -f programfile var=value ``file``…``awk` `[options] ``'BEGIN{ action;… } pattern{ action;… } END{ action;… }'` `file` `...
常用命令选项
  • -F fs:fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:

  • -v var=value:赋值一个用户定义变量,将外部变量传递给awk

  • -f scripfile:从脚本文件中读取awk命令

awk变量

变量:内置和自定义变量,每个变量前加 -v 命令选项

内置变量

(1)格式

  • FS输入字段分隔符默认为空白字符

  • OFS输出字段分隔符,默认为空白字符

  • RS :输入记录分隔符,指定输入时的换行符,原换行符仍有效

  • ORS :输出记录分隔符,输出时用指定符号代替换行符

  • NF :字段数量,共有多少字段, $NF引用最后一列,$(NF-1)引用倒数第2列

  • NR行号,后可跟多个文件,第二个文件行号继续从第一个文件最后行号开始

  • FNR :各文件分别计数, 行号,后跟一个文件和NR一样,跟多个文件,第二个文件行号从1开始

  • FILENAME :当前文件名

  • ARGC :命令行参数的个数

  • ARGV :数组,保存的是命令行所给定的各参数,查看参数

(2)演示

[root@along ~]# cat awkdemo
hello:world
linux:redhat:lalala:hahaha
along:love:youou
[root@along ~]# awk -v FS=':' '{print $1,$2}' awkdemo  #FS指定输入分隔符
hello world
linux redhat
along love
[root@along ~]# awk -v FS=':' -v OFS='---' '{print $1,$2}' awkdemo  #OFS指定输出分隔符
hello---world
linux---redhat
along---love
[root@along ~]# awk -v RS=':' '{print $1,$2}' awkdemo
hello
world linux
redhat
lalala
hahaha along
love
you
[root@along ~]# awk -v FS=':' -v ORS='---' '{print $1,$2}' awkdemo
hello world---linux redhat---along love---
[root@along ~]# awk -F: '{print NF}' awkdemo
2
4
3
[root@along ~]# awk -F: '{print $(NF-1)}' awkdemo  #显示倒数第2列
hello
lalala
love
[root@along ~]# awk '{print NR}' awkdemo awkdemo1
1
2
3
4
5
[root@along ~]# awk END'{print NR}' awkdemo awkdemo1
5
[root@along ~]# awk '{print FNR}' awkdemo awkdemo1
1
2
3
1
2
[root@along ~]# awk '{print FILENAME}' awkdemo
awkdemo
awkdemo
awkdemo
[root@along ~]# awk 'BEGIN {print ARGC}' awkdemo awkdemo1
3
[root@along ~]# awk 'BEGIN {print ARGV[0]}' awkdemo awkdemo1
awk
[root@along ~]# awk 'BEGIN {print ARGV[1]}' awkdemo awkdemo1
awkdemo
[root@along ~]# awk 'BEGIN {print ARGV[2]}' awkdemo awkdemo1
awkdemo1
自定义变量

自定义变量( 区分字符大小写)

(1)-v var=value

① 先定义变量,后执行动作print

[root@along ~]# awk -v name="along" -F: '{print name":"$0}' awkdemo
along:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:you

② 在执行动作print后定义变量

[root@along ~]# awk -F: '{print name":"$0;name="along"}' awkdemo
:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:you

(2)在program 中直接定义

可以把执行的动作放在脚本中,直接调用脚本 -f

[root@along ~]# cat awk.txt
{name="along";print name,$1}
[root@along ~]# awk -F: -f awk.txt awkdemo
along hello
along linux
along along

printf命令

比print更强大

格式

(1)格式化输出

printf` `"FORMAT"``, item1,item2, ...

① 必须指定FORMAT

不会自动换行,需要显式给出换行控制符,\n

③ FORMAT 中需要分别为后面每个item 指定格式符

(2)格式符:与item 一一对应

  • %c: 显示字符的ASCII码

  • %d, %i: 显示十进制整数

  • %e, %E: 显示科学计数法数值

  • %f :显示为浮点数,小数 %5.1f,带整数、小数点、整数共5位,小数1位,不够用空格补上

  • %g, %G :以科学计数法或浮点形式显示数值

  • %s :显示字符串;例:%5s最少5个字符,不够用空格补上,超过5个还继续显示

  • %u :无符号整数

  • %%: 显示% 自身

(3)修饰符:放在%c[/d/e/f...]之间

  • #[.#]:第一个数字控制显示的宽度;第二个# 表示小数点后精度,%5.1f

  • -:左对齐(默认右对齐) %-15s

  • +:显示数值的正负符号 %+d

演示
[root@along ~]# awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
---第一列显示小于20的字符串;第2列显示整数并换行
[root@along ~]# awk -F: '{printf "%20s---%u\n",$1,$3}' /etc/passwd
                root---0
                 bin---1
---使用-进行左对齐;第2列显示浮点数
[root@along ~]# awk -F: '{printf "%-20s---%-10.3f\n",$1,$3}' /etc/passwd
root                ---0.000    
bin                 ---1.000
---使用printf做表格
[root@along ~]# awk -F: 'BEGIN{printf "username            userid\n-----------------------------\n"}{printf "%-20s|%-10.3f|%-10s\n",$1,$3}' /etc/passwd
username            userid
-----------------------------
root                |0.000    
bin                 |1.000

操作符

格式
  • 算术操作符:

    • x+y, x-y, x*y, x/y, x^y, x%y

    • -x: 转换为负数

    • +x: 转换为数值

  • 字符串操作符:没有符号的操作符,字符串连接

  • 赋值操作符:

    • =, +=, -=, *=, /=, %=, ^=

    • ++a, --a

  • 比较操作符:

    • ==, !=, >, >=, <, <=

  • 模式匹配符:~ :左边是否和右边匹配包含 !~ :是否不匹配

  • 逻辑操作符:与&& ,或|| ,非!

  • 函数调用: function_name(argu1, argu2, ...)

  • 条件表达式(三目表达式):

    selector

    ?

    if-true-expression

    :

    if-false-expression

    • 注释:先判断selector,如果符合执行 ? 后的操作;否则执行 : 后的操作

演示

(1)模式匹配符

---查询以/dev开头的磁盘信息
[root@along ~]# df -h |awk -F: '$0 ~ /^\/dev/'
/dev/mapper/cl-root   17G  7.3G  9.7G  43% /
/dev/sda1           1014M  121M  894M  12% /boot
---只显示磁盘使用状况和磁盘名
[root@along ~]# df -h |awk '$0 ~ /^\/dev/{print $(NF-1)"---"$1}'
43%---/dev/mapper/cl-root
12%---/dev/sda1
---查找磁盘大于40%的
[root@along ~]# df -h |awk '$0 ~ /^\/dev/{print $(NF-1)"---"$1}' |awk -F% '$1 > 40'

(2)逻辑操作符

[root@along ~]# awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
root 0
bin 1
[root@along ~]# awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
root
[root@along ~]# awk -F: '!($3==0) {print $1}' /etc/passwd
bin
[root@along ~]# awk -F: '!($0 ~ /bash$/) {print $1,$3}' /etc/passwd
bin 1
daemon 2

(3)条件表达式(三目表达式)

[root@along ~]# awk -F: '{$3 >= 1000?usertype="common user":usertype="sysadmin user";print usertype,$1,$3}' /etc/passwd
sysadmin user root 0
common user along 1000

awk PATTERN 匹配部分

格式

PATTERN:根据pattern 条件,过滤匹配的行,再做处理

(1)如果未指定:空模式,匹配每一行

(2)/regular expression/ :仅处理能够模式匹配到的行,正则,需要用/ / 括起来

(3)relational expression:关系表达式,结果为“真”才会被处理

真:结果为非0值,非空字符串

假:结果为空字符串或0值

(4)line ranges:行范围

  startline(起始行),endline(结束行):/pat1/,/pat2/ 不支持直接给出数字,可以有多段,中间可以有间隔

(5)BEGIN/END 模式

  BEGIN{}: 仅在开始处理文件中的文本之前执行一次

  END{} :仅在文本处理完成之后执行

演示
[root@along ~]# awk -F: '{print $1}' awkdemo
hello
linux
along
[root@along ~]# awk -F: '/along/{print $1}' awkdemo
along
[root@along ~]# awk -F: '1{print $1}' awkdemo
hello
linux
along
[root@along ~]# awk -F: '0{print $1}' awkdemo
[root@along ~]# awk -F: '/^h/,/^a/{print $1}' awkdemo
hello
linux
along
[root@along ~]# awk -F: 'BEGIN{print "第一列"}{print $1} END{print "结束"}' awkdemo
第一列
hello
linux
along
结束

awk有意思的案例

[root@along ~]# seq 10
1
2
3
4
5
6
7
8
9
10
---因为i=0,为假,所以不打印
[root@along ~]# seq 10 |awk 'i=0'
---i=1,为真,所以全部打印
[root@along ~]# seq 10 |awk 'i=1'
1
2
3
4
5
6
7
8
9
10
---只打印奇数行;奇数行i进入时本身为空,被赋为!i,即不为空,所以打印;偶数行i进入时本身不为空,被赋为!i,即为空,所以不打印
[root@along ~]# seq 10 |awk 'i=!i'
1
3
5
7
9
---解释上一个操作,i在奇偶行的值
[root@along ~]# seq 10 |awk '{i=!i;print i}'
1
0
1
0
1
0
1
0
1
0
---只打印偶数行,是上边打印奇数行的取反
[root@along ~]# seq 10 |awk '!(i=!i)'
2
4
6
8
10
---只打印偶数行;先对i进行赋值,即不为空,刚好和打印奇数行相反
[root@along ~]# seq 10 |awk -v i=1 'i=!i'
2
4
6
8
10
​
​
seq 100 |awk 'i=!i'
awk 那段是怎么理解?
​
首先我们要了解一下awk对于未定义的变量处理方法:
​
对于数值运算,未定义变量的话awk会赋予变量初值为0
​
对于字符运算,未定义变量的话awk会赋予变量初值为空字符串
​
了解了这两条我们再看awk 'i=!i'这条命令是什么含义,awk是对文本文件一行一行处理的,seq 100命令执行后是如下形式:
​
1
​
2
​
3
​
……
​
100
​
首先它读取第一行数据,也就是1,然后进行模式匹配,i是一个未定义的变量,上面我们提到了对于数值运算,未定义变量的话初值会为0,这时i的值即为0,也就是i=!0,那么!是什么呢?!就是取反的意思,等号右边其实就是个布尔值,0为假,1为真,这里是!0,那么它就为非假,也就是为真,真的值为1,因此i=!0(1)也就相当于i=1,到此i的值为1.
 
​
i的值为1后有什么作用呢?
​
i=1说明值为真,awk会认定模式为真,这时匹配是成功的,会把第一行输出到屏幕,可能有的人会问了这里只有i=!i,没有print,它怎么输出的?awk的格式为 模式{ 动作},如果只有模式没有动作,那么匹配成功后默认的会输出整条记录,也就是说这条命令完整的写法为:
​
seq 1 100 | awk 'i=!i{print $0}'
​
为什么第二行没有输出呢?
​
前面进行第一行模式匹配的时候i的值已经由0变为了1,在进行第二行操作的时候,i=!i变成了i=!1,这样i的值就又变成了0(假),所以第二行没有输出,到了处理第三行的时候,i=!i变成了i=!0,所以会输出第三行,以此类推……这样我们就可以输出奇数行而删除偶数行了。
​
那么如何输出偶数行呢?
​
我们可以加一个if判断一下,如果i的值为真我们就输出奇数行,如果为假就输出偶数行
​
[root@LNMP ~]# seq 1 10 | awk '{i=!i;if(i) print $0}'
1
3
5
7
9
[root@LNMP ~]# seq 1 10 | awk '{i=!i;if(!i) print $0}'
2
4
6
8
10
​
看到这儿又有朋友可能会问了,为什么现在把i=!i放到动作里了呢?
​
我们看这两条命令:
​
[root@LNMP ~]# seq 1 10 | awk 'i=!i{print !i}'
0
0
0
0
0
[root@LNMP ~]# seq 1 10 | awk 'i=!i{print i}'
1
1
1
1
1
​
如果把i=!i放到模式里边它会进行匹配,把匹配的结果传递给动作,那个时候已经把不匹配的舍去了,所以我们无法用if来判断i的值。

awk高阶用法

awk控制语句—if-else判断

(1)语法

if(condition){statement;…}[else statement]  双分支
if(condition1){statement1}else if(condition2){statement2}else{statement3}  多分支

(2)使用场景:对awk 取得的整行或某个字段做条件判断

(3)演示

[root@along ~]# awk -F: '{if($3>10 && $3<1000)print $1,$3}' /etc/passwd
operator 11
games 1
[root@along ~]# awk -F: '{if($NF=="/bin/bash") print $1,$NF}' /etc/passwd
root /bin/bash
along /bin/bash
---输出总列数大于3的行
[root@along ~]# awk -F: '{if(NF>2) print $0}' awkdemo
linux:redhat:lalala:hahaha
along:love:you
---第3列>=1000为Common user,反之是root or Sysuser
[root@along ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else{printf "root or Sysuser: %s\n",$1}}' /etc/passwd
root or Sysuser: root
root or Sysuser: bin
Common user: along
---磁盘利用率超过40的设备名和利用率
[root@along ~]# df -h|awk -F% '/^\/dev/{print $1}'|awk '$NF > 40{print $1,$NF}'
/dev/mapper/cl-root 43
---test=100和>90为very good; 90>test>60为good; test<60为no pass
[root@along ~]# awk 'BEGIN{ test=100;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
very good
[root@along ~]# awk 'BEGIN{ test=80;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
good
[root@along ~]# awk 'BEGIN{ test=50;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
no pass

awk控制语句—while循环

(1)语法

while``(condition){statement;…}

注:条件“真”,进入循环;条件“假”, 退出循环

(2)使用场景

  对一行内的多个字段逐一类似处理时使用

  对数组中的各元素逐一处理时使用

(3)演示

---以along开头的行,以:为分隔,显示每一行的每个单词和其长度
[root@along ~]# awk -F: '/^along/{i=1;while(i<=NF){print $i,length($i); i++}}' awkdemo
along 5
love 4
you 3
---以:为分隔,显示每一行的长度大于6的单词和其长度
[root@along ~]# awk -F: '{i=1;while(i<=NF) {if(length($i)>=6){print $i,length($i)}; i++}}' awkdemo
redhat 6
lalala 6
hahaha 6
---计算1+2+3+...+100=5050
[root@along ~]# awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++};print sum}'
5050

awk控制语句—do-while循环

1)语法

do` `{statement;…}``while``(condition)

意义:无论真假,至少执行一次循环体

(2)计算1+2+3+...+100=5050

[root@along ~]# awk 'BEGIN{sum=0;i=1;do{sum+=i;i++}while(i<=100);print sum}'
5050

awk控制语句—for循环

(1)语法

for``(expr1;expr2;expr3) {statement;…}

  

(2)特殊用法:遍历数组中的元素

for``(var ``in` `array) {``for``-body}

  

(3)演示

---显示每一行的每个单词和其长度
[root@along ~]# awk -F: '{for(i=1;i<=NF;i++) {print$i,length($i)}}' awkdemo
hello 5
world 5
linux 5
redhat 6
lalala 6
hahaha 6
along 5
love 4
you 3
---求男m、女f各自的平均
[root@along ~]# cat sort.txt
score
[m=>170]
xiaoming m 90
xiaohong f 93
xiaohei m 80
xiaofang f 99
[root@along ~]# awk '{m[$2]++;score[$2]+=$3}END{for(i in m){printf "%s:%6.2f\n",i,score[i]/m[i]}}' sort.txt
m: 85.00
f: 96.00

和shell脚本中较相似的控制语句

break和continue
---奇数相加
[root@along ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2500
---1+2+...+66
[root@along ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
2145---奇数相加``[root@along ~]``# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'``2500``---1+2+...+66``[root@along ~]``# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'``2145

next

next:提前结束对本行处理而直接进入下一行处理(awk 自身循环)

---只打印偶数行
[root@along ~]# awk -F: '{if(NR%2!=0) next; print $1,$3}' /etc/passwd
bin 1
adm 3

awk数组

关联数组:array[index-expression]

(1)可使用任意字符串;字符串要使用双引号括起来

(2)如果某数组元素事先不存在,在引用时,awk 会自动创建此元素,并将其值初始化为“空串”

(3)若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

(4)若要遍历数组中的每个元素,要使用for 循环:for(var in array) {for-body}

演示
[root@along ~]# cat awkdemo2
aaa
bbbb
aaa
123
123
123
---去除重复的行
[root@along ~]# awk '!arr[$0]++' awkdemo2
aaa
bbbb
123
---打印文件内容,和该行重复第几次出现
[root@along ~]# awk '{!arr[$0]++;print $0,arr[$0]}' awkdemo2
aaa 1
bbbb 1
aaa 2
123 1
123 2
123 3

分析:把每行作为下标,第一次进来,相当于print ias...一样结果为空,打印空,!取反结果为1,打印本行,并且++变为不空,下次进来相同的行就是相同的下标,本来上次的值,!取反为空,不打印,++变为不空,所以每次重复进来的行都不打印

(2)数组遍历

awk 关联数组 key=>value 无序

[root@along ~]# awk 'BEGIN{abc["ceo"]="along";abc["coo"]="mayun";abc["cto"]="mahuateng";for(i in abc){print i,abc[i]}}'
coo mayun
ceo along
cto mahuateng
[root@along ~]# awk '{for(i=1;i<=NF;i++)abc[$i]++}END{for(j in abc)print j,abc[j]}' awkdemo2
aaa 2
bbbb 1
123 3
数值\字符串处理

(1)数值处理

  • rand():返回0和1之间一个随机数,需有个种子 srand(),没有种子,一直输出0.237788

演示:

[root@along ~]# awk 'BEGIN{print rand()}'
0.237788
[root@along ~]# awk 'BEGIN{srand(); print rand()}'
0.51692
[root@along ~]# awk 'BEGIN{srand(); print rand()}'
0.189917
---取0-50随机数
[root@along ~]# awk 'BEGIN{srand(); print int(rand()*100%50)+1}'
12
[root@along ~]# awk 'BEGIN{srand(); print int(rand()*100%50)+1}'
24

(2)字符串处理:

  • length([s]) :返回指定字符串的长度

  • sub(r,s,[t]) :对t 字符串进行搜索r 表示的模式匹配的内容,并将第一个匹配的内容替换为s

  • gsub(r,s,[t]) :对t 字符串进行搜索r 表示的模式匹配的内容,并全部替换为s 所表示的内容

  • split(s,array,[r]) :以r 为分隔符,切割字符串s ,并将切割后的结果保存至array 所表示的数组中,第一个索引值为1, 第二个索引值为2,…

演示:

[root@along ~]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08
[root@along ~]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
2008-08-08 08-08-08
[root@along ~]# echo "2008:08:08 08:08:08" | awk '{split($0,i,":")}END{for(n in i){print n,i[n]}}'
4 08
5 08
1 2008
2 08
3 08 08

awk自定义函数

(1)格式:和bash区别:定义函数()中需加参数,return返回值不是$?,是相当于echo输出

function name ( parameter, parameter, ... ) {
    statements
    return expression
}

(2)演示

[root@along ~]# cat fun.awk
function max(v1,v2) {
    v1>v2?var=v1:var=v2
    return var
}
BEGIN{a=3;b=2;print max(a,b)}
[root@along ~]# awk -f fun.awk
3
awk中调用shell 命令

(1)system 命令

  空格是awk 中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk 的变量外其他一律用"" 引用 起来。

[root@along ~]# awk BEGIN'{system("hostname") }'
along
[root@along ~]# awk 'BEGIN{name="along";system("echo "name)}'  注:"echo " echo后有空格
along
[root@along ~]# awk 'BEGIN{score=100; system("echo your score is " score) }'
your score is 100

(2)awk 脚本

将awk 程序写成脚本,直接调用或执行

示例:

[root@along ~]# cat f1.awk
{if($3>=1000)print $1,$3}
[root@along ~]# cat f2.awk
#!/bin/awk -f
{if($3 >= 1000)print $1,$3}
[root@along ~]# chmod +x f2.awk
[root@along ~]# ./f2.awk -F: /etc/passwd
along 1000

(3)向awk脚本传递参数

① 格式:

awkfile var=value var2=value2... Inputfile

注意 :在BEGIN 过程 中不可用。直到 首行输入完成以后,变量才可用 。可以通过-v 参数,让awk 在执行BEGIN 之前得到变量的值。命令行中每一个指定的变量都需要一个-v

② 示例

[root@along ~]# cat test.awk
#!/bin/awk -f
{if($3 >=min && $3<=max)print $1,$3}
[root@along ~]# chmod +x test.awk
[root@along ~]# ./test.awk -F: min=100 max=200 /etc/passwd
systemd-network 192

awk实战案例

统计TCP连接状态数量

筛选以tcp开头的连接状态,统计状态数并去重

netstat -tna | awk '/^tcp/{arr[$6]++}END{for(state in arr){print arr[state] ": " state}}'

统计日志中各IP访问非200状态码的次数

根据日志内容可知我们所需要的状态码信息在第九列,然后进行统计去重并取前五个ip

awk '$9!=200{arr[$1]++}END{for(i in arr){print arr[i],i}}' access.log | sort -k1nr | head -n 5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值