菜鸟笔记
提升您的技术认知

Linux文本三剑客(grep、sed、awk)

目录

grep

1、什么是grep和rgrep?

2、使用grep

2.1、命令格式

2.2、命令功能

2.3、命令参数

3、实战演示

sed

1、认识sed

2、使用sed

2.1、命令格式

2.2、常用选项options

2.3、地址定界

2.4、编辑命令command

3、sed用法演示

3.1、常用选项用法演示

3.2、sed地址定界演示

3.3、编辑命令command演示

3.4、sed高级编辑命令

awk

1、认识awk

2、使用awk

2.1、语法

2.2、常用命令选项

3、awk变量

3.1、内置变量

3.2、自定义变量

4、printf命令

4.1、格式

4.2演示

5、操作符

5.1、格式

5.3、演示

6、awk PATTERN匹配部分

6.1、格式

6.2、演示

7、awk数组

7.1、关联数组:array[index-expression]

7.2、演示

8、awk自定义函数

8.1、格式

8.2、演示

9、awk中调用shell命令

9.1、system命令

9.2、awk脚本

9.3、向awk脚本传递参数

10、grep awk sed对比

awk、grep、sed被称为Linux文本三大利器,合称为文本三剑客,也是必须掌握的Linux命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属awk功能最强大,但也是最复杂。grep更适合单纯的查找或文本匹配,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。

grep

1、什么是grep和rgrep?

         Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配到的标红)。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

        grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到标准输出,不影响源原文件内容。

        grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可以进行一些自动化的文本处理工作。

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

2、使用grep

2.1、命令格式

grep [option] pattern file

2.2、命令功能

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

2.3、命令参数

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

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

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

-c:统计匹配的行数

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

-E:扩展的正则表达式

-f FINE:从FILE过去PARRERN匹配

-F:相当于fgrep

-i:--ignore-cas饿#忽略字符大小写的差别

-n:显示匹配的行号

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

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

-s:不显示错误信息

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

-w:匹配整个单词

3、实战演示

sed

1、认识sed

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

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

2、使用sed

2.1、命令格式

sed [options] '[地址定界] command' file (s)

2.2、常用选项options

-n:不输出模式空间内容到屏幕,即不自动打印,只打印匹配到的行

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

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

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

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

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

2.3、地址定界

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

单地址:

        #:指定的行

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

地址范围:

        #,#

        #,+#

        /part1/,/part2/

        #,/part1/

~:步进

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

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

2.4、编辑命令command

d删除模式空间匹配的行,并立即启用下一轮循环

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

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

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

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

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

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

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

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

s///:查找替换,支持使用其他分隔符,如:s@@@,s###;

        加g表示行内全局替换

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

        \l:把下一个字符转换为小写

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

        \u:把下一个字符换成大写

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

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

3、sed用法演示

3.1、常用选项用法演示

[root@www test]# cat demo   #查看demo文件中的内容
aaa
bbbbb
AABBCCDD

[root@www test]# sed "/aaa/p" demo     #p是除了打印模式空间匹配到的值,还会将文件中的内容追加到模式空间后面
aaa
aaa
bbbbb
AABBCCDD

[root@www test]# sed "/aaabc/p" demo     #模式空间没有匹配到需要匹配的值,直接将文件中的内容追加到模式空间后面
aaa
bbbbb
AABBCCDD

[root@www test]# sed -n "/aaa/p" demo     #-n与p参数是对立的,-n是不输出模式空间内容到屏幕上,且不自动打印,只打印匹配到的行;p是打印当前模式空间内容,且将文本内容追加到模式空间之后,因此-n与p发生冲突,一个打印一个不打印,因此这次查询时-n起到作用,只打印匹配到的内容,注意-n与p必须同时出现,虽然发生冲突,但是去掉p的话会出现错误。
aaa

[root@www test]# sed -e "s/a/A/" -e "s/b/B/" demo     #-e是多点编辑,s///是查找替换,也就是s/查找/替换/(只替换一次);此刻的这个命令是匹配到的第一个a替换成A,匹配到的第一个b替换成B
Aaa
Bbbbb
AABBCCDD

[root@www test]# cat sedscript.txt     #查看sedscript.txt文件内容,文件内容是使用sed将A替换成a,且是全局替换,最后有一个g,g代表的是行内全局
s/A/a/g

[root@www test]# sed -f sedscript.txt demo     #-f将script写到文件中,在sed时-f指定文件路径,就可以将指定文件中的内容写到我们需要处理文件当中,此命令就是将s/A/a/g写到了demo文件中,就相当于以sed "s/A/a/g" demo的命令执行了
aaa
bbbbb
aaBBCCDD

[root@www test]# sed -e "s/a/A/g" -e "s/b/B/g" demo     #g代表的是行内全局替换,通过一行一行的形式将demo中,所有的a替换成A,b替换成B
AAA
BBBBB
AABBCCDD

[root@www test]# sed -i.bak "s/a/A/g" demo     #-i是直接将处理的结果写入文件,-i.bak是在处理的结果写入文件之前备份一份,因此下面两个文件便是对比。因为在sed中不通过-i是无法改变原文件内容的,原文件内容是不会发生变化的。
[root@www test]# cat demo
AAA
bbbbb
AABBCCDD
[root@www test]# cat demo.bak 
aaa
bbbbb
AABBCCDD
[root@www test]# 

3.2、sed地址定界演示

[root@www test]# sed -n "p" demo     #不指定行,打印全文
aaa
bbbbb
AABBCCDD

[root@www test]# sed "2s/b/B/g" demo     #将第二行的b替换成B,行内全局替换
aaa
BBBBB
AABBCCDD

[root@www test]# sed -n "1,2p" demo     #打印1,2行
aaa
bbbbb

[root@www test]# sed -n "/aaa/,/DD/p" demo     #从aaa打印到DD
aaa
bbbbb
AABBCCDD

[root@www test]# sed -n "2,/DD/p" demo     #从第2行打印到DD
bbbbb
AABBCCDD

[root@www test]# sed "1~2s/[aA]/E/g" demo     #将奇数行的a或A替换成E,1~2代表的是奇数行
EEE
bbbbb
EEBBCCDD

3.3、编辑命令command演示

[root@www test]# sed "2d" demo    #删除第2行
aaa
AABBCCDD

[root@www test]# sed -n "2p" demo     #打印第二行
bbbbb

[root@www test]# sed  "2a123" demo     #a代表在指定行后面追加文本,支持使用\n实现多行追加;2a是在第二行后面追加文本,将123追加在第二行的后面,追加后的文本会以\n实现多行追加
aaa
bbbbb
123
AABBCCDD

[root@www test]# sed "1i123" demo     #i代表在行前面插入文本,支持使用\n实现多行追加;1i是在第一行前面追加文本,将123追加在第一行的前面,追加后的文本会以\n实现多行追加
123
aaa
bbbbb
AABBCCDD

[root@www test]# sed "3c123\n456" demo     #c代表替换行为单行或多行文本,支持使用\n实现多行追加;3c是将三行替换为123,换行,在追加456
aaa
bbbbb
123
456

[root@www test]# sed -n "3w/root/test/demo3" demo     #w代表保存模式匹配的行至指定文件;3w表示将第三行的内同保存到demo3当中。注意需要使用绝对路径
[root@www test]# cat demo3    #查看demo3中的内容,果真将demo中的第三行内容保存到了demo3当中
AABBCCDD

[root@www test]# sed "1r/root/test/demo3" demo     #r代表读取指定文件的文本至模式空间中匹配的行后;1r代表读取demo3中的内容到第一行后
aaa
AABBCCDD
bbbbb
AABBCCDD

[root@www test]# sed -n "=" demo     #=代表是模式空间中的行打印行号,也就是说是打印行号
1
2
3

[root@www test]# sed -n '2!p' demo     #代表是打印除了第2行的内容
aaa
AABBCCDD

[root@www test]# sed 's@[a-z]@\u&@g' demo     #将全文的小写字母替换为大写字母
AAA
BBBBB
AABBCCDD

3.4、sed高级编辑命令

3.4.1、格式

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

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

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

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

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

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

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

d:删除模式空间中的行

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

3.4.2、一个案例和示意图演示

案例:倒叙输出文本内容

[root@www test]# cat num 
One
Two
Three

[root@www test]# sed '1!G;h;$!d' num     #1!G代表第一行不执行G命令,从第二行开始执行;$!d代表最后一行不删除
Three
Two
One

总结模式空间与保持空间 与保持空间关系

保持空间是模式空间一个临时存放数据的缓冲区,协助模式空间进行数据处理

awk

1、认识awk

        awk是一种编程语言,用于在Linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是Linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。

        awk其实不仅仅是工具软件,还是一种编程语言。只不过,文本只介绍它的命令行用法,对于大多数场合,应该足够用了。

2、使用awk

2.1、语法

awk` `[options] ``'program'` `var=value ``file``…``awk` `[options] -f programfile var=value ``file``…``awk` `[options] ``'BEGIN{ action;… } pattern{ action;… } END{ action;… }'` `file` `...

2.2、常用命令选项

-F fs:fs指定输入分隔符,fs可以是字符串或正则表达式

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

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

3、awk变量

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

3.1、内置变量

3.1.1、格式

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

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

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

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

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

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

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

FILEANAME:当前文件名

ARGC:命令行参数的个数

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

3.1.2、演示

[root@www test]# cat awkdemo     #查看awkdemo文件的内容
hello:world
linux:redhat:lalala:hahaha
along:love:youou

[root@www test]# awk -v FS=':' '{print $1,$2}' awkdemo     #-v是赋值一个用户定义变量,将外部变量传递给awk;FS是输入字段分隔符,此时的分割符为":"。此时输出字段分隔符没有被设置,因此是以默认空格为输出字符。打印文本第一列与第二列的内容。
hello world
linux redhat
along love

[root@www test]# awk -v FS=':' -v OFS='---' '{print $1,$2}' awkdemo     #FS指定输入字段分隔符被设置为":" ,OFS指定输出字段分隔符被设置为"---"
hello---world
linux---redhat
along---love

[root@www test]# awk -v RS=':' '{print $1, $2}' awkdemo      #RS是输入记录分隔符,指定输入时的换行符,换行符仍有效。意思就是说将文件中的":"看作为换行符,只要是碰见":"将当作换行符使用,原本的换行符仍然起作用
hello 
world linux
redhat 
lalala 
hahaha along
love 
youou 

[root@www test]# awk -v FS=':' -v ORS='---' '{print $1,$2}' awkdemo     #ORS是输出记录分隔符,输出时用指定符号代替换行符;只将第一列与第二列打印出来,换行符替换成了"---"
hello world---linux redhat---along love---

[root@www test]# awk -F: '{print NF}' awkdemo     #NF是指字段数量,共有多少字段
2
4
3

[root@www test]# awk -F: '{print $(NF-1)}' awkdemo     #$NF代表引用最后一列,$(NF-1)代表引用倒数第二列
hello
lalala
love

[root@www test]# cat awkdemo1
hello:world
linux:redhat:lalala:hahaha
along:love:youou
[root@www test]# awk '{print NR}' awkdemo awkdemo1     #NR代表行号,后面可以跟多个文件,第二个文件行号继续从第一个文件最后的行号开始
1
2
3
4
5
6

[root@www test]# awk END'{print NR}' awkdemo awkdemo1     #END打印最后一行的行号
6

[root@www test]# awk '{print FNR}' awkdemo awkdemo1     #FNR代表个文件分别计数,行号,后跟一个文件和NR一样,跟多个文件,第二个文件行号从1开始
1
2
3
1
2
3

[root@www test]# awk '{print FILENAME}' awkdemo     #FILENAME代表时当前文件的文件名
awkdemo
awkdemo
awkdemo

[root@www test]# awk 'BEGIN {print ARGC}' awkdemo awkdemo1      #ARGC代表的是命令行参数的个数,其中三个参数分别是awk,awkdemo,awkdemo1
3

[root@www test]# awk 'BEGIN {print ARGV[0]}' awkdemo awkdemo1     #ARGV代表的是将命令行中的参数以数组的形式,可以进行查看,此时是查看第一个参数。
awk
[root@www test]# awk 'BEGIN {print ARGV[1]}' awkdemo awkdemo1 
awkdemo
[root@www test]# awk 'BEGIN {print ARGV[2]}' awkdemo awkdemo1 
awkdemo1

3.2、自定义变量

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

3.2.1、-v var=value

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

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

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

[root@www test]# awk -F: '{print name":"$0;name="along"}' awkdemo     #第一行为什么没有变量名呢,原因是awk是以行来运行的,命令在运行第一行时,变量名此时还没有被声明,因此第一行没有变量名
:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:youou

3.2.2、在progarm中直接定义

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

[root@www test]# awk -F: -f awk.txt awkdemo
along hello
along linux
along along

4、printf命令

比print更强大

4.1、格式

4.1.1、格式化输出

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

①必须指定FORMAT

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

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

4.1.2格式符:与item一一对应

%c:显示字符的ASCⅡ码

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

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

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

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

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

%u:无符号整数

%%:显示%自身

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

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

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

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

4.2演示

[root@www test]# awk -F: '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4


[root@www test]# awk -F: '{printf "%20s---%u\n",$1,$3}' /etc/passwd     #打印第一行显示小于20的字符串;第2列显示整数并换行(右对齐)
                root---0
                 bin---1
              daemon---2
                 adm---3
                  lp---4

[root@www test]#  awk -F: '{printf "%-20s---%-10.3f\n",$1,$3}' /etc/passwd     #使用-进行左对齐;第二列显示浮点数
root                ---0.000     
bin                 ---1.000     
daemon              ---2.000     
adm                 ---3.000     
lp                  ---4.000  

[root@www test]# awk -F: 'BEGIN{printf "username            userid\n-----------------------------\n"}{printf "%-20s|%-10.3f\n",$1,$3}' /etc/passwd     #使用printf做表格
username            userid
-----------------------------
root                |0.000     
bin                 |1.000     
daemon              |2.000     
adm                 |3.000     
lp                  |4.000 

5、操作符

5.1、格式

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

        -x:转换为负数

        +x:转换为数值

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

赋值操作符:

        =,+=,-=,*=,%=,^=

        ++,--

比较操作符:

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

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

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

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

条件表达式(三目运算符):selector?if-ture-expression:if-false-expression

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

5.3、演示

①模式匹配符

[root@www test]# df -h | awk -F: '$0 ~ /^\/dev/'     #查询以/dev开头的磁盘信息
/dev/mapper/centos-root   36G  8.7G   28G  25% /
/dev/sda1               1014M  171M  844M  17% /boot

[root@www test]# df -h | awk '$0 ~ /^\/dev/{print $(NF-1)}"---"$1'     #只显示磁盘使用状况和磁盘名
Filesystem               Size  Used Avail Use% Mounted on
25%
/dev/mapper/centos-root   36G  8.7G   28G  25% /
devtmpfs                 1.4G     0  1.4G   0% /dev
tmpfs                    1.4G     0  1.4G   0% /dev/shm
tmpfs                    1.4G   12M  1.4G   1% /run
tmpfs                    1.4G     0  1.4G   0% /sys/fs/cgroup
17%
/dev/sda1               1014M  171M  844M  17% /boot
tmpfs                    280M   12K  280M   1% /run/user/42
tmpfs                    280M     0  280M   0% /run/user/0

[root@www test]# df -h | awk '$0 ~ /^\/dev/{print $(NF-1)"---"$1}' |awk -F% '$1 > 20'     #查找磁盘大于20%的
25%---/dev/mapper/centos-root

②逻辑操作符

[root@www test]# awk -F: '$3>=0 && $3<=100 {print $1,$3}' /etc/passwd
    #查询第三列大于等于三,小于等于一百的,并且打印第一列和第三列
root 0
bin 1
daemon 2
adm 3
lp 4

[root@www test]# awk -F: '$3==0 || $3>=1000{print $1}' /etc/passwd     #查询第三列为0或第三列大于等于1000,满足前面的的两个条件,则直接打印第一列
root
nfsnobody
centos

[root@www test]# awk -F: '!($3==0){print $1}' /etc/passwd
bin

[root@www test]# awk -F: '!($0 ~ /bash$/) {print $1,$3}' /etc/passwd
bin 1
daemon 2
adm 3
lp 4

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

[root@www test]# awk -F: '{$3 >= 1000?usrtype="common user":usertype="sysadmin user";print usertype,$1,$3}' /etc/passwd
sysadmin user root 0
sysadmin user bin 1
sysadmin user daemon 2
sysadmin user adm 3
sysadmin user lp 4

6、awk PATTERN匹配部分

6.1、格式

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

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

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

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

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

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

(4)line ranges:行范围

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

(5)BEGIN/END模式

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

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

6.2、演示

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

7、awk数组

7.1、关联数组:array[index-expression]

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

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

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

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

7.2、演示

[root@www test]# cat awkdemo2     #查看awkdemo2文件中的内容
aaa
bbbb
aaa
123
123
123

[root@www test]# awk '!arr[$0]++' awkdemo2     #去除重复的行;awkdemo2中的内容在arr[]数组中都是键名,aaa第一次进入数组中是没有值的,所以第一次arr为0,取反之后arr为1,在awk中,只有为真的时候才会打印输出,因此第一次打印出aaa;第二次是bbbb,当bbbb进入arr数组中,因为是第一次进入所以也是0,取反之后为1,输出bbb;第三次是aaa再次进入数组中,此时$0为1,取反之后就为0,因此没有打印处理啊;第四次是123第一次进入数组,没有值因此也是0,在取反之后为1,所以输出打印;第五次是123,此时$0为2,取反为0,因此不输出;第六次是123,此时$0为1,取反为0,也不输出。
aaa
bbbb
123


[root@www test]# awk '{!arr[$0]++;print $0,arr[$0]}' awkdemo2     #打印文件内容,和该行重复第几次出现
aaa 1
bbbb 1
aaa 2
123 1
123 2
123 3

8、awk自定义函数

8.1、格式

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

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

8.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

9、awk中调用shell命令

9.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

9.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

9.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

10、grep awk sed对比

grep 主要用于搜索某些字符串;

sed,awk 用于处理文本 ;

  grep基本是以行为单位处理文本的**; 而awk可以做更细分的处理,通过指定分隔符将一行(一条记录)划分为多个字段,以字段为单位处理文本。**awk中支持C语法,可以有分支条件判断、循环语句等,相当于一个小型编程语言。

  awk功能比较多是一个编程语言了。 grep功能简单,就是一个简单的正则表达式的匹配。 awk的功能依赖于grep。

  grep可以理解为主要作用是在一个文件中查找过滤需要的内容。awk不是过滤查找,而是文本处理工具,是把一个文件处理成你想要的格式。

  AWK的功能是什么?与sed和grep很相似,awk是一种样式扫描与处理工具。但其功能却大大强于sed和grep。awk提供了极其强大的功能:它几乎可以完成grep和sed所能完成的全部工作,同时,它还可以可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上,awk的确拥有自己的语言:awk程序设计语言,awk的三位创建者已将它正式定义为:样式扫描和处理语言。 使用awk的第一个理由是基于文本的样式扫描和处理是我们经常做的工作,awk所做的工作有些象数据库,但与数据库不同的是,它处理的是文本文件,这些文件没有专门的存储格式,普通的人们就能编辑、阅读、理解和处理它们。而数据库文件往往具有特殊的存储格式,这使得它们必须用数据库处理程序来处理它们。既然这种类似于数据库的处理工作我们经常会遇到,我们就应当找到处理它们的简便易行的方法,UNIX有很多这方面的工具,例如sed 、grep、sort以及find等等,awk是其中十分优秀的一种。

  使用awk的第二个理由是awk是一个简单的工具,当然这是相对于其强大的功能来说的。的确,UNIX有许多优秀的工具,例如UNIX天然的开发工具C语言及其延续C++就非常的优秀。但相对于它们来说,awk完成同样的功能要方便和简捷得多。这首先是因为awk提供了适应多种需要的解决方案:从解决简单问题的awk命令行到复杂而精巧的awk程序设计语言,这样做的好处是,你可以不必用复杂的方法去解决本来很简单的问题。例如,你可以用一个命令行解决简单的问题,而C不行,即使一个再简单的程序,C语言也必须经过编写、编译的全过程。其次,awk本身是解释执行的,这就使得awk程序不必经过编译的过程,同时,这也使得它与shell script程序能够很好的契合。最后,awk本身较C语言简单,虽然awk吸收了C语言很多优秀的成分,熟悉C语言会对学习awk有很大的帮助,但awk本身不须要会使用C语言——一种功能强大但需要大量时间学习才能掌握其技巧的开发工具。

  使用awk的第三个理由是awk是一个容易获得的工具。与C和C++语言不同,awk只有一个文件(/bin/awk),而且几乎每个版本的UNIX都提供各自版本的awk,你完全不必费心去想如何获得awk。但C语言却不是这样,虽然C语言是UNIX天然的开发工具,但这个开发工具却是单独发行的,换言之,你必须为你的UNIX版本的C语言开发工具单独付费(当然使用D版者除外),获得并安装它,然后你才可以使用它。

  基于以上理由,再加上awk强大的功能,我们有理由说,如果你要处理与文本样式扫描相关的工作,awk应该是你的第一选择。在这里有一个可遵循的一般原则:如果你用普通的shell工具或shell script有困难的话,试试awk,如果awk仍不能解决问题,则便用C语言,如果C语言仍然失败,则移至C++。

  sed是一个非交互性文本流编辑器。它编辑文件或标准输入导出的文本拷贝。sed编辑器按照一次处理 一行的方式来处理文件(或者输入)并把输出送到屏幕上。你可以在vi和ex/ed编辑器里识别他的命令。sed把当前正在处理的行保存在一个临时缓存里,这个缓存叫做模式空间。一但sed完成了对模式空间里的行的处理(即对该行执行sed命令),就把模式空间的行送到屏幕上(除非该命令要删除该行活禁止打印)。处理完该行之后,从模式空间里删除它,然后把下一行读入模式空间,进行处理,并显示。当输入文件的最后一行处理完后,sed终止。通过把每一行存在一个临时缓存里并编辑该行,初始文件不会被修改或被破坏。