欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

(马哥教育)awk入门(2) 有大用

action 就是任何 awk执行的内部语句,可以是赋值语句,可以是命令,可以是函数调用,反正任何经常使用的语句在这里都可以用

控制语句:  

1, if-else

语法:if (condition) {then-body} [ else { else-body } ]                   

 then-body一般要用花括号括起来吧  if 后面的语句如果只执行一行语句,可以不用花括号括起来

例子 

awk -F: '{if ($1=="root") print $1,"Admin";else print $1,"Common User"}' /etc/passwd

awk -F: '{if ($1=="root") printf "%-15s: %s\n", $1,"Admin";else printf  "%-15s: %s\n", $1,"Common User"}' /etc/passwd

awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd



2,while

语法 while (condition) {statement1;statement2;...}

awk -F: '{i=1;while(i<=3){print $i;$i++}' /etc/passwd                    (i是内部使用的变量)


3,do-while            (无论条件满足不满足,上来先循环一下)

语法 do {statement1;statement2;...}  while (condition) 

awk -F: '{i=1;do {print $i;i++} while(i<=3)}' /etc/passwd


4, for

语法: for ( varible assignment; condition;iteration process) {statement1;statement2;...}

awk -F: '{for(i=1;i<3;i++) print $i}' /etc/passwd


for循环还可以遍历数组元素

语法: for (i in array) {statement1,statement2,...}

awk -F: '$NF !~ /^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd


5,case

语法 switch (expression) { case VALUE or /REGEXP/: statement1;statement2;...default  statement1;...}



6, break 和 continue

常用于循环或case语句中


7, next

提前结束对本行文本的处理,并接着处理下一行


image.png



[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){print $i;i++}}' /etc/passwd


(上面的意思是 把 $1,$2,$3,$4 都显示出来,awk的语法与 bash的语法有所不同,(bash中 i=1;echo $i 的值就是1,而不是echo $1的值)


(记住循环处理的是当前行里面的切片(段)(片段),是对当前行的循环)(其实用的场景并不多,因此只要看懂语法结构就行了)

(将每一行进行切片后,对每一个片段分别做处理)


image.png



[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){printf $i;i++}}' /etc/passwd

image.png



[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){printf $i;printf " ";                             i++};printf "\n"}' /etc/passwd


 

image.png


[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){printf "%10s",$i;i++};printf "\n"}' /etc/passwd

image.png



[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=NF){printf $i; printf "    ";i+=2};printf "\n"}' /etc/passwd


while循环打印出奇数列(字段)的值image.png



[root@localhost ~]# awk -F: '{for(i=1;i<NF;i+=2) { printf $i;printf "  ";};printf "\n"}' /etc/passwd

for循环打印出奇数列(字段)的值

image.png


[root@localhost ~]# awk -F: '{for(i=2;i<NF;i+=2) { printf $i;printf "  ";};printf "\n"}' /etc/passwd


for循环打印偶数列(字段)的值image.png



内置变量

ORS: (output record separator) 输出的换行符

OFS:(out field separator) 输出的字段分割符,默认也是空白字符

FS:(field separator) 读入的字段分割符,默认是空白字符  (读入文件的段分割符的符号)

RS: (Record separator) 默认换行符

NR: (The number of input records(row)), 行数awk 命令所处理的记录数,如果有多个文件,这个数目会把处理的多个文件中行统一计数

NF:  (Number of Filed),当前行(记录)的field个数

FNR: (field number record(row)) 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数,当前行所在的这个文件的行数

ARGV:(argument varibale)数组,保存命令行本身这个字符串,如 awk '{print $0}' a.txt b.txt 这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt

ARGC:(argument count)awk命令的参数的个数

image.png




shell 中 使用数组 遍历数组 shell中数组的键是数字

for i in (0..10)

 print A[$i]


awk 中使用数组 遍历数组   这里A遍历的是数组的下标,是把ARRAY的下标值 每一次赋值给A,要记住是下标,awk中数组的键可以为字符串

for (A in ARRAY) { print ARRAY[A] }



对于awk来讲,任何一个变量:在使用之前,如果没做声明的话,它的初始值为0,可以拿来直接用的

S["m"] 0

S["m"]++ 1

S["m"]++ 2



awk中使用数组                (变量是命名的一段存储空间,数组是可以存储多个数据的,一段连续的存储空间)

array[index-expression]


index-expression可以使用任意字符串:需要注意的是,如果某数据元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数组是否存在某元素,需要使用index in array的方式.


要遍历数组中的每一个元素,需要使用如下的特殊结构:

for (var in array) {statement1,...}

其中,var用于引用数组下标:


例子:

netstat -n | awk '/^tcp/'  (++S[$NF]) END (for(a in S) print a,S[a]}'

每出现一被/^tcp/模式匹配到的行,数组[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引;


awk '{counts[$1]++}; END{for (url in counts) print counts[url],url}' /var/log/httpd/access_log

用法与上一个例子相同,用于统计某日志文件中IP地址的访问量


awk的内置函数

split(string,array [ , fieldsep [ , seps ] ] )

功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中:

clients[1]  切割后第一个元素的下标为1,不是0


能够统计当前我们服务器上处于连接会话状态的所有的ip以及它的个数 并按从大到小排序,只显示前50个

(如果太多,有ddos攻击之嫌)

netstat -ant | awk '/:80/{split($5,clients,":");IP[clients[1]]++}END{for ( i in IP) {print IP[i],i}}' | sort -rn | head -50


length([string])

功能:返回string字符串中字符的个数


substr(string,start  [, length] )

功能: 取string字符串中的子串,从 start开始,取length个


system(command)

功能: 执行系统command并将结果返回至awk命令


systime()

功能:取系统当前时间


awk [options] 'PATTERN{action}' input_file

    -F:输入字段分隔符

    -v:定义变量


常见的模式类型:


1,Regexp:正则表达式,格式为 /regular expression/


2,expression:表达式,其值非0或为非空字符串时满足条件,如: $1 ~ /foo/ 或 $1 == "megedu" ,用运算符~(匹配)和~!(不匹配)


3,Ranges: 指定的匹配范围,格式为pat1,pat2  (类似于sed '1,3' 从第一行到第三行, 而且也支持  /bash/,/awk/ 第一次匹配到bash的行开始,到第一次匹配到awk的行结束,的中间的所有行)


4,BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次 (在真正的action之前 或 action之后执行一次,仅执行一次)


5,Empty(空模式):匹配任意输入行  就是不指任意模式



print item1,item2

printf format,item1,item2,...






shell 中数组下标为 0,1,2,3,4... 数组变量前要加美元符$

image.png



awk 中数组下标为 任意字符串(当然也可以使用数值来引用,但使用什么得自己去定义)   数组变量前不需要加美元符$

image.png


[root@localhost ~]# awk 'BEGIN{A[x]="hello";A[y]="world"; print A[x],A[y]}'

                            (记住这里字符串 hello 和 world 要用双引号,否则假如用单引号的话,会与 action外面的单引号冲突)

                            (x,y也要用双引号,否则会把x 和 y 当作变量了,因为没有变量,就初始化成了A[0] (A[1]),因此就是显示A[0] A[1]),的值了,

                                但是我测了 A[0] A[1] 都是空,所以他的解释不对)

world world



[root@localhost ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world"; print A["x"],A["y"]}'

                            (记住这里字符串 hello 和 world 要用双引号,否则假如用单引号的话,会与 action外面的单引号冲突)

                            (x,y也要用双引号,否则会把x 和 y 当作变量了,因为没有变量,就初始化成了A[0] (A[1]),因此就是显示A[0] A[1]),的值了,

                              但是我测了 A[0] A[1] 都是空,所以他的解释不对

hello world

[root@localhost ~]#


[root@localhost ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world"; for(B in A){ print A[B]}}'

hello

world

[root@localhost ~]#



image.png



[root@localhost ~]# netstat -ant  (显示当前系统上每一个已处于建立的连接(TCP连接)或者已存在的连接(TCP连接)的状态信息)

(显示每一个连接的状态信息)

-a, --all, --listening     display all sockets (default: connected)

-a, --all

       Show  both  listening and non-listening sockets.  With the --interfaces option, show inter-

       faces that are not marked

image.png

image.png



[root@ebs-22233 ~]# netstat -ant | grep "LISTEN" | wc -l

15

[root@localhost ~]#


[root@ebs-22233 ~]# netstat -ant | grep "ESTABLISHED" | wc -l

2

[root@ebs-22233 ~]#



[root@ebs-22233 ~]# netstat -ant | awk '{S[$NF]++}END{for(A in S) print A,S[A]}'            打印每一种状态的值 

TIME_WAIT 40

established) 1

SYN_SENT 1

State 1

ESTABLISHED 2

SYN_RECV 1

LISTEN 15





打印每一种状态的值   下面这个再过滤一下 (过滤tcp)

[root@ebs-22233 ~]# netstat -ant | awk '$1 ~ /tcp/{S[$NF]++}END{for(A in S) print A,S[A]}'

TIME_WAIT 76

ESTABLISHED 3

SYN_RECV 1

LISTEN 15

[root@ebs-22233 ~]#



打印每一种状态的值   下面这个再过滤一下 (过滤tcp) , 下面这个显示更友好的格式  (这里在format中使用冒号,分隔各个片断)

[root@ebs-22233 ~]# netstat -ant | awk '$1 ~ /tcp/{S[$NF]++}END{for(A in S) printf "%-10s:%s\n", A,S[A]}'

TIME_WAIT :110

ESTABLISHED:2

SYN_RECV  :1

LISTEN    :15

[root@ebs-22233 ~]#





[root@ebs-22233 ~]# cat /etc/passwd

image.png


[root@localhost ~]# awk -F: '$NF !~ /^$/{SHELL[$NF]++}END{for(A in SHELL) print A,SHELL[A]}' /etc/passwd

(排除掉空之后,看不同的shell,各个多少个)


image.png




看access_log 每一个客户(每一个ip)访问多少次

[root@ebs-22233 ~]# tail -n 5000 /www/wdlinux/httpd-2.2.31/logs/access_log | awk '{IP[$1]++}END{for(A in IP) print A,IP[A]}'

image.png




# netstat -ant

image.png




普通分类: