linux awk命令详解


详细介绍AWK的文章,推荐去朱双印的个人博客,10分好评的个人博客,传送门

 

本文章仅为个人精简参考使用,不适合初学者,详细的介绍文章,请用以上的传送门

 

也可以稍微参考一下博客园:https://www.cnblogs.com/isykw/p/6258781.html

也可以参考CSDN https://blog.csdn.net/sunchengquan/article/details/80276842

本文包括

  • AWK简介
  • awk基本语法
  • awk常用命令选项
  • awk的几种模式
  • awk的内置变量
  • awk设置定义变量
  • awk模式的定义,空模式,关系运算模式,BEGIN模式,END模式,正则表达式模式
  • awk 在用 {x,y} 这种正则时,需要加参数
  • awk 支持if else, for ,while等控制语句
  • awk 计算日志中ip的数量
  • awk 把两个文件内的指定列,合并成一个文件
  • awk编程,善用FNR NR
  • awk数学运算
  • awk 生成随机数(利用awk的自带函数)
  • awk中使用shell的环境变量

AWK简介

awk是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan这三个人创造的,awk由这个三个人的姓氏的首个字母组成。

awk早期是在unix上实现的,所以,我们现在在linux的所使用的awk其实是gawk,也就是GNU awk,简称为gawk,awk还有一个版本,New awk,简称为nawk,但是linux中最常用的还是gawk。

awk其实是一门编程语言,它支持条件判断、数组、循环等功能。所以,我们也可以把awk理解成一个脚本语言解释器。

awk  更适合格式化文本,以文件的行为处理单位的,对文本进行较复杂格式处理

AWK基础

基本语法如下

awk [options] 'Pattern{Action}' file
awk '{ 

     BEGIN{stat1} 
     BEGIN{stat2} 
     pattern1{action1} 
     pattern2{action2} 
     ... 
     patternn{actionn} 
     {默认动作,无条件,始终执行} 

     END{stat1} 
     END{stat2} 
}'

 

常用命令选项

-F 指定输入分隔符,fs可以是字符串或正则表达式,如 -F ':' , 默认的隔符是空格

-v var=value -v是一种选项,var是一个变量的名称,value是一个变量的值,有很多内置的变量名称

-v FS=':' 指定输入分隔符为: 和 -F 类似

-v OFS='###' 指定 输出分隔符 ,默认输出分隔符为空格,可以换成任意的输出分割符
-f scripfile 从脚本文件中读取awk命令

 

awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk

如果只是显示/etc/passwd的账户
#cat /etc/passwd |awk  -F ':'  '{print $1}' root daemon bin sys

 

AWK 包含两种特殊的模式:BEGIN 和 END。

BEGIN 模式指定了处理文本之前需要执行的操作:

END 模式指定了处理完所有行之后所需要执行的操作:

以下实例展示了-v FS 指定输入分隔符 和 -v OFS 指定输出分隔符 指定BEGIN 和 END

awk 处理 /etc/passwd  获取 $1,$7的数据

而账户与shell之间以'++++'分割,

而且在第一行添加文字 "name,shell",

在最后一行添加"blue,/bin/nosh"。

[root@cnblogs ~]# cat /etc/passwd |awk  -v FS=':' -v OFS="++++" 'BEGIN {print "name,shell"}  {print $1,$7} END {print "blue,/bin/nosh"}'
name,shell
root++++/bin/bash
bin++++/sbin/nologin
daemon++++/sbin/nologin
...
... blue,
/bin/nosh

 

awk内置变量

awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

ARGC               命令行参数个数
ARGV               ARGV内置变量表示的是一个数组,这个数组中保存的是命令行所给定的参数。这样解释还是很模糊,不容易理解,我们来看看示例。
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                各文件分别记录的行号
FS                 FS: field separator设置输入域分隔符,等价于命令行 -F选项
NF                 列数,number of the field,当前处理行的总列数(被分成几列)
NR                 行数,number of the row,当前处理文本行的行号
OFS                OFS:output field separator 输出字段分隔符, 默认为空白字符
ORS                ORS:output row separator 输出记录分隔符(输出换行符),输出时用指定符号代替换行符
RS                 RS:row separator 输入记录分隔符(输入换行符), 指定输入时的换行符

除了内置变量,也可以定义自定义变量

有两种定义方法

方法一:-v varname=value  变量名区分字符大小写。

方法二:在program中直接定义。

[root@cnblogs ~]# awk -v myVAR="testVAR" 'BEGIN{print myVAR}'
testVAR
[root@cnblogs ~]# awk 'BEGIN{myVAR="testVAR";print myVAR}'
testVAR

也可以一次定义多个,如

[root@cnblogs ~]# awk 'BEGIN{myVAR1="testVAR1";myVAR2="testVAR2";print myVAR1,myVAR2}'
testVAR1 testVAR2

 

统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:

[root@cnblogs ~]#  awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync
filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

使用printf替代print,可以让代码更加简洁,易读

[root@cnblogs ~]# awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync
filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

AWK模式的概念就是条件

"模式"这个词听上去文绉绉的,不是特别容易理解,那么我们换一种说法,我们把"模式"换成"条件",可能更容易理解,那么"条件"是什么意思呢?我们知道,awk是逐行处理文本的,也就是说,awk会先处理完当前行,再处理下一行,如果我们不指定任何"条件",awk会一行一行的处理文本中的每一行,如果我们指定了"条件",只有满足"条件"的行才会被处理,不满足"条件"的行就不会被处理。这样说是不是比刚才好理解一点了呢?这其实就是awk中的"模式"。

再啰嗦一遍,当awk进行逐行处理的时候,会把pattern(模式)作为条件,判断将要被处理的行是否满足条件,是否能跟"模式"进行匹配,如果匹配,则处理,如果不匹配,则不进行处理。

 

以下是AWK模式的示例 NF=2 或者 NF>2 是条件,也就是模式

[root@cnblogs ~]# awk 'NF==2 {print $0}' /etc/passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin

[root@cnblogs ~]# awk 'NF>2 {print $0}' /etc/passwd
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin

 

AWK支持正则表达式匹配

 

 

 

 

 

 

 

 

 

 

 

 

 

 

除此之外,还要注意以下两点

1、当在awk命令中使用正则模式时,使用到的正则用法属于"扩展正则表达式"。

2、当使用 {x,y} 这种次数匹配的正则表达式时,需要配合--posix选项或者--re-interval选项。

 

 

 

 

 

awk的"模式(Pattern)",

空模式 没有条件,每行都处理

关系运算模式 根据条件,处理符合条件的行

BEGIN 模式

END 模式

正则模式

 

AWK支持"if...else if...else"这样的"控制语句"

 

 

 

 

 

 AWK支持for 循环,while  循环,continue,break,do ... while 循环

详细请参考,朱双印的博客:http://www.zsythink.net/archives/2062

#for循环语法格式1
for(初始化; 布尔表达式; 更新) {
//代码语句
}
 
#for循环语法格式2
for(变量 in 数组) {
//代码语句
}
 
#while循环语法
while( 布尔表达式 ) {
//代码语句
}
 
#do...while循环语法
do {
//代码语句
}while(条件)

 

 

 

 

 

 

 

 

为了方便判断和阅读,最好将多个语句用{}括起来。awk分支结构允许嵌套,其格式为:

示例:

awk 'BEGIN{
test=100;
if(test>90){
print "very good"
}
else if(test>60){
print "good"
}
else{
print "no pass"
}
}'

very good

 

自定义变量用; 分号结尾


while语句
示例:

awk 'BEGIN{
test=100;
total=0;
while(i<=test){
total+=i;
i++;
}
print total;
}'
5050

 

 

 


上图中,我们使用了一个空模式,一个END模式。

 

 

 

 

 

如下示例,计算人名出现的次数

awk '{for (i=1;i<=NF;i++) {count[$i]++}} END{for(j in count){print j,count[j]}}' test4

 

 

 

 以下示例得到小于100的随机数,使用了rand() 和 srand(),int() 函数

用srand()是因为,如果只使用rand(),第一次的数值不会变化,每次都是一样的随机数

[root@jenkins ~]# awk 'BEGIN{srand();print rand()}'
0.0698597
[root@jenkins ~]# awk 'BEGIN{srand();print 100*rand()}'
79.413
[root@jenkins ~]# awk 'BEGIN{srand();print int(100*rand())}'
73
[root@jenkins ~]# 

更多awk函数用法,请参考:

http://www.zsythink.net/archives/2113

https://www.cnblogs.com/isykw/p/6258781.html

 

按照列合并两个文件

[root@cnblogs ~]# cat a
1 2
1 2
1 2
1 2
1 2
[root@cnblogs ~]# cat b
3 4
3 4
3 4
3 4
3 4
[root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$0}} {if(FNR!=NR){print d[FNR],$0}}' a b
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
[root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$1}} {if(FNR!=NR){print d[FNR],$2}}' a b
1 4
1 4
1 4
1 4
1 4
[root@cnblogs ~]# awk 'FNR==NR {x[FNR]=$0} FNR!=NR{print x[FNR],$0}' a b
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
[root@cnblogs ~]# 

 

a和b 有相同的列,把相同的列结合在一起

[root@cnblogs ~]# cat a
116 t1
117 t2
118 t3
[root@cnblogs ~]# cat b
116 1000
117 1500
118 800
[root@cnblogs ~]#  awk 'NR==FNR{a[$1]=$2}NR!=FNR{print a[$1],$2}'  a b
t1 1000
t2 1500
t3 800
[root@cnblogs ~]# awk '{print NR ,FNR ,$1,$2}' a b
1 1 116 t1
2 2 117 t2
3 3 118 t3
4 1 116 1000
5 2 117 1500
6 3 118 800

 awk数学运算示例

求1除以3结果保留一位小数,并且用%号表示数值

[root@cnblogs ~]# t1=1
[root@cnblogs ~]# t2=3
[root@cnblogs ~]# awk 'BEGIN{printf "%.1f%\n",("'$t1'"/"'$t2'")*100}'
33.3%
[root@cnblogs ~]# 

 

awk中使用shell的环境变量

 

第一种方法,使用-v ,定义变量可以引用变量

 

[root@cnblogs ~]# abc=66666
[root@cnblogs ~]# awk -v myVAR="$abc" 'BEGIN{print myVAR}'
66666

 

 

[root@cnblogs ~]# var="test"
[root@cnblogs ~]# awk -v var="$var" 'BEGIN{print var}'
test

 第二种方法,在awk中直接引用,使用字符串变量 ,

注意使用前格式必须是先用单引号括住再用双引号括住,如:
"
'$var'"
如果变量中含有空格或者特殊符号,需要如下
"'"$var"'"

如果不是用脚本文件方式执行,直接在shell里执行,需要先用export var=test 导出为环境变量,

这样其后的awk子进程才会有该变量。

 

[root@cnblogs ~]# var="test"
[root@cnblogs ~]# awk 'BEGIN{print "'$var'"}'
test

 

[root@cnblogs ~]# var="this is a test"
[root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}'
this is a test
[root@cnblogs ~]# 
[root@cnblogs ~]# export var="this is a test"
[root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}'
this is a test
[root@cnblogs ~]# 

 

所有IP的连接数统计

awk 'BEGIN{while("netstat -an"|getline){if( $5 ~ /[1-255]/){split($5,t1,":");tarr[t1[1]]++;}}for(k in tarr){print k,tarr[k] | "sort -r -n -k2";}};'

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM