Linux awk学习

零、awk标准语法

[root@wohaoshuai1 bbb]# echo "abcd" |awk 'BEGIN{print "wohaoshuai"} /a/ {print length($0)} END{print "hehe"}'
wohaoshuai
4
hehe
[root@wohaoshuai1 bbb]# echo "abcd" |awk 'BEGIN{print "wohaoshuai"} /bb/ {print length($0)} END{print "hehe"}'
wohaoshuai
hehe
[root@wohaoshuai1 bbb]# echo "abcd" |awk 'BEGIN{print "wohaoshuai"} /b/ {print length($0)} END{print "hehe"}'
wohaoshuai
4
hehe

一、awk基本操作

  1、打印文件中信息

[root@wohaoshuai1 bbb]# awk '{print}' 1.txt 
abaca        dafdsaf         23    dsfsfsdf
dsafbe        dfsdfds         34    dadsgr4edxzgvcxiksjkl
fsbsfads      ejfklsdnmfkldsj        45    ds;lfekopmkldnvksda
sfdksnme3    dsfsknfkl353426        56    4t5t435
sf3ew53wefsty    dsf3e5t345        67    3e435fdsf6

  2、打印文件中第一列信息

[root@wohaoshuai1 bbb]# awk '{print $1}' 1.txt 
abaca
dsafbe
fsbsfads
sfdksnme3
sf3ew53wefsty

  3、打印第一列第三列,中间使用制表符隔开

[root@wohaoshuai1 bbb]# awk '{print $1 "\t" $3}' 1.txt 
abaca    23
dsafbe    34
fsbsfads    45
sfdksnme3    56
sf3ew53wefsty    67

  4、添加行号(NR)

[root@wohaoshuai1 bbb]# awk '{print NR "\t" $1 "\t" $2 "\t" $3}' 1.txt 
1    abaca    dafdsaf    23
2    dsafbe    dfsdfds    34
3    fsbsfads    ejfklsdnmfkldsj    45
4    sfdksnme3    dsfsknfkl353426    56
5    sf3ew53wefsty    dsf3e5t345    67

  5、打印每一行有多少列(NF)

[root@wohaoshuai1 bbb]# awk '{print NF "\t" $0}' 1.txt 
4    abaca        dafdsaf         23    dsfsfsdf
4    dsafbe        dfsdfds         34    dadsgr4edxzgvcxiksjkl
4    fsbsfads      ejfklsdnmfkldsj        45    ds;lfekopmkldnvksda
6    sfdksnme3    dsfsknfkl353426        56    4t5t435 esf aaa
5    sf3ew53wefsty    dsf3e5t345        67    3e435fdsf6 eee

  6、打印出第三列等于67的行

[root@wohaoshuai1 bbb]# awk '$3==67 {print $0}' 1.txt 
dsafbe        dfsdfds         67    dadsgr4edxzgvcxiksjkl
sf3ew53wefsty    dsf3e5t345        67    3e435fdsf6 eee
sf3ew53wefsty   dsf3e5t345              67      3e435fdsf6 ees

  7、打印出第一列等于abaca的行

[root@wohaoshuai1 bbb]# awk '$1=="abaca" {print $0}' 1.txt 
abaca        dafdsaf         23    dsfsfsdf

  8、如何把一行竖排的数据转换成横排?

[root@wohaoshuai1 bbb]# cat 3.txt
abc"
"xxabc
sfasabc
"xxabcxx"    abc
"a bc"        bcd
abcsdfdsfeabc    dsfdabc
abcdefg
ab c
a b c
a c
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '{printf("%s,",$0)}' 3.txt
abc","xxabc,sfasabc,"xxabcxx"    abc,"a bc"        bcd,abcsdfdsfeabc    dsfdabc,abcdefg,ab c,a b c,a c,adc,bbb,a.c,[root@wohaoshuai1 bbb]# 

   9、大哥操作

grep "Dec/2018" pyplatform_access.log|awk '{a[$1]++}END{for(i in a){print a[i]" "i}}'|sort -nr |head -10

 

二、awk内部变量

  1、NF 竖行数量

当此行有4列时就打印此行
[root@wohaoshuai1 bbb]# awk 'NF==4 {print NF "\t" $0}' 1.txt 
4    abaca        dafdsaf         23    dsfsfsdf
4    dsafbe        dfsdfds         67    dadsgr4edxzgvcxiksjkl
4    fsbsfads      ejfklsdnmfkldsj        45    ds;lfekopmkldnvksda

  2、NR 横行数量

当NR为4,即第四行才打印
[root@wohaoshuai1 bbb]# awk 'NR==4 {print NR "\t" $0}' 1.txt 
4    sfdksnme3    dsfsknfkl353426        56    4t5t435 esf aaa

  3、FS 定义当前输入所用的分隔符

[root@wohaoshuai1 bbb]# awk 'BEGIN{FS=","} {print $1 "\t" $2}'
1 2 4
1 2 4    
1,2,3,4
1    2
12,23,34
12    23

  4、OFS 输出分隔符

[root@wohaoshuai1 bbb]# awk 'BEGIN{OFS=","} {print $1,$2}'   #相当于$1和$2之间的逗号由开始默认的空格变为了, 
1 2 3 4 5
1,2
1 2 3 45 45
1,2
将输入分隔符定义为,输出分隔符定义为,
[root@wohaoshuai1 bbb]# awk 'BEGIN{OFS=",";FS=","} {print $1,$2}' 1 2 3 4 1 2 3 4, 1,2,3,4 1,2

  5、FILENAME 文件名

同时统计两个文件
[root@wohaoshuai1 bbb]# awk '{print NR "\t" $0}' 1.txt 2.txt 
1    abaca        dafdsaf         23    dsfsfsdf
2    dsafbe        dfsdfds         67    dadsgr4edxzgvcxiksjkl
3    fsbsfads      ejfklsdnmfkldsj        45    ds;lfekopmkldnvksda
4    sfdksnme3    dsfsknfkl353426        56    4t5t435 esf aaa
5    sf3ew53wefsty    dsf3e5t345        67    3e435fdsf6 eee
6    sf3ew53wefsty   dsf3e5t345              67      3e435fdsf6 ees
7    sffbbb hello
8    aekjfdk slkfjdsklfnk dlskfjej
9    123 345 dskfj345 123556
10    123df dgfg fedkgfj45 skdllfe980
11    

输出行号,文件名和相应信息
[root@wohaoshuai1 bbb]# awk '{print NR "\t" FILENAME "\t" $0}' 1.txt 2.txt 
1    1.txt    abaca        dafdsaf         23    dsfsfsdf
2    1.txt    dsafbe        dfsdfds         67    dadsgr4edxzgvcxiksjkl
3    1.txt    fsbsfads      ejfklsdnmfkldsj        45    ds;lfekopmkldnvksda
4    1.txt    sfdksnme3    dsfsknfkl353426        56    4t5t435 esf aaa
5    1.txt    sf3ew53wefsty    dsf3e5t345        67    3e435fdsf6 eee
6    1.txt    sf3ew53wefsty   dsf3e5t345              67      3e435fdsf6 ees
7    2.txt    sffbbb hello
8    2.txt    aekjfdk slkfjdsklfnk dlskfjej
9    2.txt    123 345 dskfj345 123556
10    2.txt    123df dgfg fedkgfj45 skdllfe980
11    2.txt    

  6、给列赋值

方法1、
[root@wohaoshuai1 bbb]# awk '{$3="xxx";print $0}' 1.txt 
abaca dafdsaf xxx dsfsfsdf
dsafbe dfsdfds xxx dadsgr4edxzgvcxiksjkl
fsbsfads ejfklsdnmfkldsj xxx ds;lfekopmkldnvksda
sfdksnme3 dsfsknfkl353426 xxx 4t5t435 esf aaa
sf3ew53wefsty dsf3e5t345 xxx 3e435fdsf6 eee
sf3ew53wefsty dsf3e5t345 xxx 3e435fdsf6 ees
方法2、
[root@wohaoshuai1 bbb]# awk '$3="xxx" {print $0}' 1.txt 
abaca dafdsaf xxx dsfsfsdf
dsafbe dfsdfds xxx dadsgr4edxzgvcxiksjkl
fsbsfads ejfklsdnmfkldsj xxx ds;lfekopmkldnvksda
sfdksnme3 dsfsknfkl353426 xxx 4t5t435 esf aaa
sf3ew53wefsty dsf3e5t345 xxx 3e435fdsf6 eee
sf3ew53wefsty dsf3e5t345 xxx 3e435fdsf6 ees

  7、打印倒数第一列和倒数第二列

[root@wohaoshuai1 bbb]# awk '{print $NF}' 1.txt 
dsfsfsdf
dadsgr4edxzgvcxiksjkl
ds;lfekopmkldnvksda
aaa
eee
ees
[root@wohaoshuai1 bbb]# awk '{print $(NF-1)}' 1.txt 
23
67
45
esf
3e435fdsf6
3e435fdsf6

  8、获取外部变量

    a、获得普通外部变量

[root@361way ~]# test='awk test code'
[root@361way ~]# echo | awk  '{print test}' test="$test"
awk test code
注:awk '{action}' 变量名=变量值,这样传入变量,可以在action中获得值。 注意:变量名与值放到'{action}'后面。

    b、BEGIN程序块中变量

[root@361way ~]# test='awk Begin test'
[root@361way ~]# echo | awk -v test="$test" 'BEGIN{print test}'
awk Begin test
[root@361way ~]# echo | awk -v test="$test" '{print test}'
awk Begin test

[root@wohaoshuai1 bbb]# echo |awk -v test="$test" -v test2="test2" 'BEGIN {print test,test2}'
awk test code test2

使用:awk –v 变量名=变量值 [–v 变量2=值2 …] 'BEGIN{action}'格式时,用-v 传入变量可以在BEGIN、END或省略3种类型的action 中都可以获得到变量值,但顺序在action前面。而且最前面的echo管道不能少。

三、awk运算

  1、在awk中会自动根据实际情况判断定义的变量是字符串还是数字

[root@wohaoshuai1 bbb]# awk '{a=1;b=2; print a + b}' #也支持加减乘除
3

[root@wohaoshuai1 bbb]# awk '{a=1;b=2; print a b}' #此处表示将ab两个字符串拼接起来
12

[root@wohaoshuai1 bbb]# awk '{a=1;b=2; print a,b}' #此处表示将ab两个字符串输出出来
1 2

四、正则表达式

  1、/abc/ 如果字符串中包含abc三个字符那么表示符合正则表达式内容

[root@wohaoshuai1 bbb]# cat 3.txt 
"abc"
"xxabc"
"xxabcxx"
"a bc"
ab c
a b c
bbb
[root@wohaoshuai1 bbb]# awk '/abc/ {print $0}' 3.txt 
"abc"
"xxabc"
"xxabcxx"

  2、/a.c/ #中间的点表示任何一个字符

[root@wohaoshuai1 bbb]# cat 3.txt 
"abc"
"xxabc"
"xxabcxx"
"a bc"
ab c
a b c
a c
adc
bbb
[root@wohaoshuai1 bbb]# awk '/a.c/ {print $0}' 3.txt 
"abc"
"xxabc"
"xxabcxx"
a c
adc

  3、转义

[root@wohaoshuai1 bbb]# cat 3.txt 
"abc"
"xxabc"
"xxabcxx"
"a bc"
ab c
a b c
a c
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '/a\.c/ {print $0}' 3.txt 
a.c

  4、^ 和 $

匹配以abc开头的字符
/^abc/
[root@wohaoshuai1 bbb]# cat 3.txt 
abc"
"xxabc"
"xxabcxx"
"a bc"
abcdefg
ab c
a b c
a c
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '/^abc/ {print $0}' 3.txt 
abc"
abcdefg
匹配以abc结尾的字符
/abc$/
[root@wohaoshuai1 bbb]# cat 3.txt 
abc"
"xxabc
sfasabc
"xxabcxx"
"a bc"
sdfdsfeabc
abcdefg
ab c
a b c
a c
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '/abc$/ {print $0}' 3.txt 
"xxabc
sfasabc
sdfdsfeabc

  5、[] #匹配方括号中的任意一个

/a[xyz]c/ #可以匹配到axc,ayc,azc

中间出现一个小写或大写的字符
/a[a-zA-Z]c/

^第二个意思
/a[^a-z]c/ 写在中括号前面表示不匹配,此处表示a和c中间匹配不是a-z的字符

  6、*表示匹配零到多次,+ 表示匹配一次到多次

    /a*b/ #表示匹配0到多个a
    b
    ab
    aab
    /a+b/ #表示匹配一到多个a
    ab
    aab
    aaab

  7、? #跟在一个字母后面表示这个字母可以出现也可以不出现

    /a?b/  #表示a可以有也可以没有,因此可以匹配 b 或者 ab

  8、{}

    {3} #表示前面的字母必须出现三次   #/ab{3}c/
    {3,5} #表示前面的字母可以出现3-5次    #/ab{3,5}c/
    {3,}    #表示前面的字母可以出现3到多个    #/ab{3,}c/

  9、() 

    /(ab)+c/ #表示ab可以反复出现,如abc,ababc,abababc

 五、awk高级用法

  1、awk赋值运算,赋值语句运算符:= += -= *= /= %= ^= **

例如:a+=5;等价于a=a+5

# awk 'BEGIN{a=5;a+=5;print a}'
10

  2、awk正则运算

输出包含有root的行,并打印用户名和UID及原行内容

[root@localhost ~]# awk -F: '/root/ {print $1,$3,$0}' /etc/passwd
root 0 root:x:0:0:root:/root:/bin/bash
operator 11 operator:x:11:0:operator:/root:/sbin/nologin
我们发现找到了两行,如果我们想找root开头的行就要这样写:

awk -F: '/^root/' /etc/passwd

  3、awk三目运算

# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
ok
# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
err
三目运算其实就是一个判断运算,如果为真则输出?后的内容,如果为假则输出:后的内容

  4、awk的循环运用

    a、if语句运用

[root@localhost ~]# awk 'BEGIN{ test=100;if(test>90){ print "very good";} else{print "no pass";}}'
verygood
每条命令后用;结尾

    b、while循环运用 计算从1累加到100的值

[root@wohaoshuai1 bbb]# awk 'BEGIN{test=100;num=0; while(i<=test) {num+=i;i++};{print num}}'
5050

    c、for循环的运用

[root@wohaoshuai1 bbb]# awk 'BEGIN{test=0; for (i=0;i<=100;i++) {test+=i};{print test}}'
5050

    d、循环数组

[root@wohaoshuai1 bbb]# a='a b c'
[root@wohaoshuai1 bbb]# awk -v a="$a" 'BEGIN{split(a,str," ");for(i in str) {print str[i]}}'
a
b
c

    e、do循环的运用

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

  5、awk的数组运用

    a、数组是awk的灵魂,处理文本中最不能少的就是它的数组处理,因为数组索引(下标)可以是数字和字符串。
    b、在awk中数组叫做关联数组(associative arrays)。
    c、awk 中的数组不必提前声明,也不必声明大小。
    d、数组元素用0或空字符串来初始化,这根据上下文而定。
    e、一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。

[root@wohaoshuai1 bbb]# awk -F: 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd 
0 root
1 bin
2 daemon
3 adm
4 lp
5 sync
6 shutdown
7 halt
8 mail
9 operator
10 games
11 ftp
12 nobody
13 avahi-autoipd
14 systemd-bus-proxy
15 systemd-network
16 dbus
17 polkitd
18 apache
19 abrt
20 libstoragemgmt
21 tss

六、awk字符串函数的运用

  1、sub,匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的时候.

[root@wohaoshuai1 bbb]# awk '{ sub(/abc/, "mytest"); print $0}' 3.txt
mytest"
"xxmytest
sfasmytest
"xxmytestxx"    abc
"a bc"        bcd
mytestsdfdsfeabc    dsfdabc
mytestdefg
ab c
a b c
a c
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '{ sub(/abc/, "mytest",$2); print $0}' 3.txt
abc"
"xxabc
sfasabc
"xxabcxx" mytest
"a bc"        bcd
abcsdfdsfeabc dsfdmytest
abcdefg
ab c
a b c
a c
adc
bbb
a.c

    a、上面第一个例子在整个记录中匹配,替换只发生在第一次匹配发生的时候。如要在整个文件中进行匹配需要用到gsub

    b、上面第二个例子在整个记录的第二个域中进行匹配,替换只发生在第一次匹配发生的时候。

  2、gsub,整个文档中进行匹配

[root@wohaoshuai1 bbb]# awk '{ gsub(/abc/, "mytest"); print $0}' 3.txt
mytest"
"xxmytest
sfasmytest
"xxmytestxx"    mytest
"a bc"        bcd
mytestsdfdsfemytest    dsfdmytest
mytestdefg
ab c
a b c
a c
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '{ gsub(/abc/, "mytest",$2); print $0}' 3.txt
abc"
"xxabc
sfasabc
"xxabcxx" mytest
"a bc"        bcd
abcsdfdsfeabc dsfdmytest
abcdefg
ab c
a b c
a c
adc
bbb
a.c

    a、第一个例子在整个文档中匹配test,匹配的都被替换成mytest。

    b、第二个例子在整个文档的第一个域中匹配,所有匹配的都被替换成mytest。

  3、index,返回子字符串第一次被匹配的位置,偏移量从位置1开始 index(string, substring)

  4、substr,返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串

[root@wohaoshuai1 bbb]# awk '{ print substr( $1, 1,7 ) }' 3.txt
abc"
"xxabc
sfasabc
"xxabcx
"a
abcsdfd
abcdefg
ab
a
a
adc
bbb
a.c
[root@wohaoshuai1 bbb]# awk '{ print substr( $1, 1,11) }' 3.txt
abc"
"xxabc
sfasabc
"xxabcxx"
"a
abcsdfdsfea
abcdefg
ab
a
a
adc
bbb
a.c

    上面例子中分别为打印每行1,7个字符和1,11个字符

  5、split,可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割 split( string, array, field separator ) split( string, array )

[root@wohaoshuai1 bbb]# awk -v a="20:18:00" 'BEGIN{ split( a, time, ":" ); for(i in time) {print time[i]} }'
20
18
00

  6、length,返回记录的字符数 length( string ),length( list/dict ),length

[root@wohaoshuai1 bbb]# awk 'BEGIN{ print length( "test" ) }'
4
[root@wohaoshuai1 bbb]# awk '{print length}' 3.txt
4
6
7
13
11
21
7
4
5
3
3
3
3

    a、第一个实例返回test字符串的长度。

    b、第二个实例返回testfile文件中第条记录的字符数。

  6、match,返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位 置,RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串 match( string, regular expression )

[root@wohaoshuai1 bbb]# awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start}'
11
[root@wohaoshuai1 bbb]# awk 'BEGIN{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
11 11 4  

    a、第一个实例打印以连续小写字符结尾的开始位置,这里是11。

    b、第二个实例还打印RSTART和RLENGTH变量,这里是11(start),11(RSTART),4(RLENGTH)。

  7、toupper和tolower,可用于字符串大小间的转换,该功能只在gawk中有效 toupper( string ) tolower( string )

[root@wohaoshuai1 bbb]# awk 'BEGIN{ print toupper("test"), tolower("TEST") }'
TEST test

 

posted @ 2019-01-07 15:19  Presley  阅读(377)  评论(0编辑  收藏  举报