gawk编辑器使用格式:

gawk  options  program  file

    -F        指定分隔符

    -f         指定文件中读取程序

    -v var-value    定义一个变量及其默认值

    -mf        指定最大字段数 max field

    -mr        指定最大数据行 max record,可以用'NR<10{print $1}'代替

    -W         指定兼容模式或警告等级

program的语法格式 '{language}'


例:

gawk '{print "hello world"}'

注意:程序会等待你的输入,但是输出都是hello world,使用Ctrl+D结束



一、基本使用


使用数据字段变量:

$1  $2  $3 分别代表第一二三个数据字段,$0 代表一整行数据,分隔符为空格或制表符,使用-F可以指定分割符

例1:

cat  data.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
gawk  '{print $1  $2}'  data.txt
Thequick
Thequick

例2:

gawk -F: '{print  $1  $2}' /etc/passwd


在程序脚本中使用多个命令:

用分号分割,如:'{one;  two;  three}'

例:

echo  "My name is Rich"  |  gawk  '{$4="Christine";  prinrt $0}'

My name is Christine

先给$4赋值,然后将整行文本输出,输出时第四个字段替换成了新值


从文件中读取程序:

cat  script.gawk
{
text = "'s home directory is "
print $1 text $6
}

gawk  -F:  -f  script.gawk  /etc/passwd


BEGIN、END的使用:

BEGIN            读取数据之前执行一段脚本

END               处理完数据之后执行一段脚本

例:

gawk  'BEGIN{ print "This is Title" } { print $0 } END{ print "This is end"}' demo.txt

This is Title            #先输出了标题

The quick brown fox jumps over the lazy dog.

This is end            #最后输出页脚

注意:几个脚本要在引号之内



二、使用变量


内置变量:

gawk数据字段和记录变量

FILEWIDTHS            定义每个数据字段的确切宽度,由空格分割的一列数字

FS                            输入字段分格符,默认空格

OFS                         输出字段分格符,默认空格

RS                            输入记录分隔符,默认一行为一条记录

ORS                         输出记录分格符


FS:指定字段分隔符,-F优先级高于FS,不建议混用

]# awk -v FS=':' '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
libstoragemgmt 998
abrt 173
rpc 32
sshd 74
postfix 89
chrony 997
ntp 38

引用FS变量:

]# awk -v FS=':' '{print $1FS$3}' /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-network:192
dbus:81
polkitd:999
libstoragemgmt:998
abrt:173
rpc:32
sshd:74
postfix:89
chrony:997
ntp:38


OFS(output field string):输出字段分隔符

]# awk -v FS=':' -v OFS='=' '{print $1,$3}' /etc/passwd
root=0
bin=1
daemon=2
adm=3
lp=4
sync=5
shutdown=6
halt=7
mail=8
operator=11
games=12
ftp=14
nobody=99
systemd-network=192
dbus=81
polkitd=999
libstoragemgmt=998
abrt=173
rpc=32
sshd=74
postfix=89
chrony=997
ntp=38


FIELDWIDTHS:字段分割长度,定义字段宽度,并依此分割字符串。

cat data.txt
21.2133.34.55.555
43.4433.55564.2.6
gawk 'BEGIN{FIELDWIDTHS="1 4 4 3"}{print $1,$2,$3,$4}' test.txt
2 1.21 33.3 4.5
4 3.44 33.5 556


RS(record string):行分隔符,一般结尾都是换行符作为换行符,但是可以用RS指定换行符

]# echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@k8stest-01 ~]# 
[root@k8stest-01 ~]# 
[root@k8stest-01 ~]# 
[root@k8stest-01 ~]# echo {a..z} | awk -v RS=' ' '{print $0}'
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z

例2:

cat data.txt
Riley
123-456-789

Frank
234-567-890
gawk 'BEGIN{FS="\n"; RS=""} {print $1,$2}' data.txt

输入记录分隔符RS设置为一个空行为一条记录:RS="",字段分隔符设置为换行FS="\n"

处理结果如下:

Riley 123-456-789
Frank 234-567-890


ORS:输出换行分隔符

]# echo {a..z} | awk -v RS=' ' -v ORS='=' '{print $0}'
a=b=c=d=e=f=g=h=i=j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z


数据变量:更多的awk内建变量

ARGC            当前命令行参数个数

ARGIND        当前文件在ARGV中的位置

ARGV            包含命令行参数的数组

COMVFMT    数字的转换格式,同printf,默认值%.6 g

ENVIRON      当前环境变量和值组成的关联数组

ERRON          读取或关闭输入文件的错误号

FILENAME     输入数据文件的文件名,要处理文件的文件名

IGNORECASE    值为非零时,忽略命令中字符串的大小写

NF                 数据文件中的字段总数 number field,一共有多少个字段

NR                 已近处理的输入记录数 number record,当前处理的行号

FNR               当前数据文件的数据行 file number record,多个文件情况下每个文件单独统计行号

OFMT            数字的输出格式,默认值为%.6 g

RLENGTH      由match函数所匹配的子字符串长度

RSTART         由match函数所匹配的子字符串的起始位置


输出环境变量ENVIRON:

例:

gawk 'BEGIN{
print ENVIRON["HOME"]    #读取环境变量中的HOME环境变量
print ENVIRON["PATH"]    #读取环境变量中的PATH环境变量
}'


NF:列数,一共有多少列

]# awk -v FS=":" '{print NF}' /etc/passwd
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
7
[root@k8stest-01 ~]# awk -v FS=":" '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown
/sbin/halt
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin

取列值:

]# df -h | awk -F'[ %]+' '{print $(NF-1)}'
已用
0
0
12
0
5
30
0


NR:标记行号

]# awk -F: '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
11 games
12 ftp
13 nobody
14 systemd-network
15 dbus
16 polkitd
17 libstoragemgmt
18 abrt
19 rpc
20 sshd
21 postfix
22 chrony
23 ntp
24 tcpdump

NR:取IP值

]# ifconfig eth0 | awk 'NR==2{print $2}'
192.168.199.15

NR:记录处理过的所有行的行数

]# awk '{print NR,FILENAME}' /etc/issue /etc/os-release 
1 /etc/issue
2 /etc/issue
3 /etc/issue
4 /etc/os-release
5 /etc/os-release
6 /etc/os-release
7 /etc/os-release
8 /etc/os-release
9 /etc/os-release
10 /etc/os-release
11 /etc/os-release
12 /etc/os-release
13 /etc/os-release
14 /etc/os-release
15 /etc/os-release
16 /etc/os-release
17 /etc/os-release
18 /etc/os-release
19 /etc/os-release

FNR:每处理一个文件就重新计数

]# awk '{print FNR,FILENAME}' /etc/issue /etc/os-release 
1 /etc/issue
2 /etc/issue
3 /etc/issue
1 /etc/os-release
2 /etc/os-release
3 /etc/os-release
4 /etc/os-release
5 /etc/os-release
6 /etc/os-release
7 /etc/os-release
8 /etc/os-release
9 /etc/os-release
10 /etc/os-release
11 /etc/os-release
12 /etc/os-release
13 /etc/os-release
14 /etc/os-release
15 /etc/os-release
16 /etc/os-release

ARGC:当前命令行参数个数

]# awk '{print ARGC}' /etc/issue /etc/redhat-release 
3
3
3
3

ARGV:包含命令行参数的数组

]# awk '{print ARGV[0]}' /etc/issue /etc/redhat-release 
awk
awk
awk
awk
~]# awk '{print ARGV[1]}' /etc/issue /etc/redhat-release 
/etc/issue
/etc/issue
/etc/issue
/etc/issue
~]# awk '{print ARGV[2]}' /etc/issue /etc/redhat-release 
/etc/redhat-release
/etc/redhat-release
/etc/redhat-release
/etc/redhat-release

printf格式化输出:

%s:显示字符串
%d, %i:显示十进制整数
%f:显示为浮点数
%e, %E:显示科学计数法数值
%c:显示字符的ASCII码
%g, %G:以科学计数法或浮点形式显示数值
%u:无符号整数
%%:显示%自身

修饰符:

#[.#]  第一个数字控制显示的宽度;第二个#表示小数点后精度,如:%3.1f
-      左对齐(默认右对齐) 如:%-15s    
+      显示数值的正负符号     如:%+d

示例:

awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}' /etc/passwd

示例:

]# awk -F: '{printf "%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdlibstoragemgmtabrtrpcsshdpostfixchronyntptcpdumpnginx[root@nginx ~]# 
[root@nginx ~]# 
[root@nginx ~]# 
[root@nginx ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-network
dbus
polkitd
libstoragemgmt
abrt
rpc
sshd
postfix
chrony
ntp
tcpdump

示例:

]# awk -F: '{printf "%20s\n",$1}' /etc/passwd
                root
                 bin
              daemon
                 adm
                  lp
                sync
            shutdown
                halt
                mail
            operator
               games
                 ftp
              nobody
     systemd-network
                dbus
             polkitd
      libstoragemgmt
                abrt
                 rpc
                sshd
             postfix
              chrony
                 ntp

示例:

]# awk -F: '{printf "%-20s %-10d\n",$1,$3}' /etc/passwd
root                 0         
bin                  1         
daemon               2         
adm                  3         
lp                   4         
sync                 5         
shutdown             6         
halt                 7         
mail                 8         
operator             11        
games                12        
ftp                  14        
nobody               99        
systemd-network      192       
dbus                 81        
polkitd              999       
libstoragemgmt       998       
abrt                 173       
rpc                  32        
sshd                 74        
postfix              89        
chrony               997       
ntp                  38

打印表头:

]# awk -F: 'BEGIN{print "USER UID \n---------------------------"}{print $1,$3}' /etc/passwd
USER UID 
---------------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
sshd 74
postfix 89
chrony 998

打印表格:

]# awk -F: 'BEGIN{printf "--------------------------------\n%-20s|%10s|\n--------------------------------\n","username","uid"}
{printf "%-20s|%10d|\n--------------------------------\n",$1,$3}
END{print "finished"}' /etc/passwd
--------------------------------
username            |       uid|
--------------------------------
root                |         0|
--------------------------------
bin                 |         1|
--------------------------------
daemon              |         2|
--------------------------------
adm                 |         3|
--------------------------------
lp                  |         4|
--------------------------------
sync                |         5|
--------------------------------
shutdown            |         6|
--------------------------------
halt                |         7|
--------------------------------
mail                |         8|
--------------------------------
operator            |        11|
--------------------------------
games               |        12|
--------------------------------
ftp                 |        14|
--------------------------------
finished


使用正则:

]# ifconfig eth0 | awk '/netmask/{print $2}'
192.168.199.15

取区间值:

]# seq 10 | awk 'NR>=5 && NR<=8'
5
6
7
8

取某个字符开头到某个字符结尾区间的值:

]# awk '/^b/,/^s/' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync


自定义变量:

赋值:

gawk 'BEGIN{
test = "This is a test"
print test
}'

运算:

gawk 'BEGIN{x = 4; x = x * 4; print x}'   #在BEGIN里面的变量不用$符号

gawk编辑器包含了标准的算术运算符


在命令行上给变量赋值:

例1:

cat script.gawk
BEGIN{FS=" "} {print $n}
gawk  -f  script.gawk  n=2  data.txt      #在命令行上直接给脚本中的变量赋值

处理结果,输出了第二列:

xxx2
xxx2
xxx2

命令行赋值在BEGIN部分变量不可用,-v参数可以解决这个问题。


例2:使用-v参数

cat  script.gawk

BEGIN{ print "The value is ",n ; FS=" "}{print $n}

gawk -v n=2 -f script.gawk  test.txt           # 使用-v方法赋值要提前

处理结果:

The value is  2
xxx2
xxx2
xxx2


定义数组变量:

gawk只有关联数组

例:

gawk 'BEGIN{
        test[a]="this is a test" ;
        print test[a] ;
}'
this is a test


数组可以直接参与运算:

gawk 'BEGIN{
        test[1] = 12 ;
        test[2] = 3 ;
        print value = test[1] + test[2];
}'
15


遍历数组:

gawk 'BEGIN{
test["a"] = 1
test["b"] = 2
        for(val in test){
                print "The value is ",test[val]
        }
}'
The value is  1
The value is  2


删除数组命令:

delete  array[index]   删除数组元素

gawk 'BEGIN{
        test["a"] = 1 ;
        test["b"] = 2 ;
        for (key in test){
                print "The value is ",test[key] ;
        }
        delete test["b"] ;
        for ( key in test){
                print test[key] ;
        }
}'
The value is  1
The value is  2
1



三、表达式


使用模式:和BEGIN、END关键字一样,/hello/也是一种模式。

正则表达式:

gawk 'BEGIN{FS=","}  /hello/{print $0}' data.txt        #会匹配含有hello的行


匹配操作符:

$1 ~ /^data/        第一个字段是以data开头的记录。$1表示第一个数据字段,/^data/表示以data开头的记录

例:

gawk 'BEGIN{FS=","} $1 ~ /^xxx/{print $0}' test.txt

ccc1,xxx2,xxx3,xxx4


排除表达式:

$1 !~ /expression/        除了这个表达式之外的全部

gawk -F: '$1 !~ /root/{print $1,$NF}' /etc/passwd

除了第一个字段为root的记录之外的全部打印出第一字段和最后一个字段。

处理结果:

bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin


数学表达式:

例 :

gawk -F: '$4 == 0{ print $1 }' /etc/passwd     #这个例子显示了属于root组的用户

可用的表达式有:==        <=        >=        <        >

也可以用字符串比较:

gawk -F, '$1 == "data"{ print $1 }'  data.txt



四:结构化命令


if语句:

gawk '{ if ($1 > 20 ) print $1}' data.txt

长格式:

gawk '{
        if ($1 > 20){
                print $1
        }else{
                print $2
        }
}'

缩成一行:

gawk '{ if ()  print $1 ; else print $2 }' data.txt


while语句:

gawk '{
        i = 0
        while ( i < 4 ){
                i++
        }
        print "the value is ",i
}'


do-while语句:

gawk '{
        x = 0;
        do{
                x++;
        }while( x < 20 );
        print $x ; 
}'

for语句:

gawk '{
        for(i = 0 ; i < 10 ; i++){
                print i ;
        }
}'


格式化输出:

格式化指定符的控制字母:

c            将一个数作为ASCII字符显示

d            显示一个整数值

i             同d

e            科学计数法显示一个数

f             显示一个浮点值

g            用科学计数法或浮点数显示(选择较短的格式)

o            显示一个八进制值

s             显示文本字符串

x             显示一个十六进制值

X            显示一个十六进制值,但用大写字母A-F

例:

printf "%16s   %s\n" , $1 , $4
printf "%-16    %s\n" , $1 , $4        #“-”表示左对齐



五、函数


数学函数:

atan2(x, y)        x/y的反正切,x和y以弧度为单位

cos(x)               x的余弦,x以弧度为单位

exp(x)               x的指数函数

int(x)                 x的整数部分,取整

log(x)                x的自然对数

rand()                0到1之间的随机数

sin(x)                 x的正弦,x以弧度为单位

sqrt(x)               x的平方根

srand(x)            为计算随机数指定一个种子值

位运算函数:

and(v1, v2)            位与运算

compl(val)             val的补运算

lshift(val, count)    将值val左移count位

or(v1, v2)               位或运算

rshift(val, count)    右移count位

xor(v1, v2)             v1和v2的按位异或运算

字符串运算:

asort(s, [d])              排序

asorti(s, [d])             排序

gensub(r, s, h, [t])    匹配替换

gsub(r, s, [t])            匹配替换


length:统计字符长度

]# awk 'BEGIN{print length("aaa")}'
3


asort

排序后,建名为数字索引1,2,3等等,值为排序后的值。

例:

gawk 'BEGIN{
        var["a"]=1
        var["g"]=2
        var["b"]=3
        asort(var, test)
        for(x in test){
                print x,test[x]
        }
        print test[1]
}'

键名和键值

1 1
2 2
3 3


asorti

键名为索引1,2,3等等,键值为原来的键名

例:

gawk 'BEGIN{
var["a"]=1
var["g"]=2
var["b"]=3
asorti(var, test)
        for(x in test){
            print x,test[x]
        }
        print test[1]
}'
1 a
2 b
3 g


split

用FS或正则分格字段,放入第二个参数

例:

gawk 'BEGIN{FS=","}{
        split($0, var)
        print var[1], var[3]            #索引从1开始
}'  test.txt
xxx1 xxx3
ccc1 xxx3
xxx1 xxx3


调用内置命令:

]# awk 'BEGIN{system("hostname")}'
nginx


时间函数:

mktime()        将一个按YYYY MM DD HH MM SS格式的日期转换成时间戳,STD格式

strftime()        将时间戳转换成格式化的日期

systime()        返回当前时间的时间戳

例:

gawk 'BEGIN{
        date = systime()
        day = strftime("%A, %B, %d, %Y", date)
        print day
}'
星期一, 十一月, 13, 2017


自定义函数:

函数必须放在所有代码块之前,如下:

gawk '
function myprint(){
        printf "%-16s - %s\n", $1,$2
}
BEGIN{FS="\n" ; RS=""}
{
        myprint()
}' test.txt
Rion             - 213-234-455
Stephone         - 543-178-234


创建函数库:

例:

函数库的内容:cat funclib.gawk 

function myprint(){
        printf "%-16s - %s\n", $1,$2
}
function hello{
        print $4
}

脚本中的内容:cat script.gawk 

BEGIN{FS="\n" ; RS=""}
{
        myprint()
}

使用-f命令来引入函数库和处理脚本,但是两个脚本不可以放在一起:

gawk  -f  funclib.gawk  -f  script.gawk  test.txt


实例:

处理这样一个脚本:

name1,team1,100,123,109

name2,team2,130,140,122

name3,team3,129,123,109

处理脚本如下:

#!/bin/bash
for team in $(gawk -F, '{print $2}' test.txt |uniq)
do
        echo $team;
        gawk -v team=$team 'BEGIN{FS="," ; total=0}{
                if($2==team){
                        total += $3 + $4 + $5;
                }
        }
        END{
                avg = total / 6;
                print "total for", team, "is", total, ",the avgrage is ",avg
        }' test.txt
done

处理结果如下:

total for team1 is 332 ,the avgrage is  55.3333
total for team2 is 392 ,the avgrage is  65.3333
total for team3 is 361 ,the avgrage is  60.1667