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/passwdBEGIN、END的使用:
BEGIN 读取数据之前执行一段脚本
END 处理完数据之后执行一段脚本
例:
gawk 'BEGIN{ print "This is Title" } { print $0 } END{ print "This is end"}' demo.txtThis 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:38OFS(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=38FIELDWIDTHS:字段分割长度,定义字段宽度,并依此分割字符串。
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 556RS(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
0NR:标记行号
]# 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 tcpdumpNR:取IP值
]# ifconfig eth0 | awk 'NR==2{print $2}'
192.168.199.15NR:记录处理过的所有行的行数
]# 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-releaseFNR:每处理一个文件就重新计数
]# 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-releaseARGC:当前命令行参数个数
]# awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3
3ARGV:包含命令行参数的数组
]# 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-releaseprintf格式化输出:
%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.txtccc1,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.txtwhile语句:
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")}'
3asort
排序后,建名为数字索引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 gsplit
用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