欢迎各位兄弟 发布技术文章
这里的技术是共享的
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
提前结束对本行文本的处理,并接着处理下一行
[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的值)
(记住循环处理的是当前行里面的切片(段)(片段),是对当前行的循环)(其实用的场景并不多,因此只要看懂语法结构就行了)
(将每一行进行切片后,对每一个片段分别做处理)
[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){printf $i;i++}}' /etc/passwd
[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){printf $i;printf " "; i++};printf "\n"}' /etc/passwd
[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=4){printf "%10s",$i;i++};printf "\n"}' /etc/passwd
[root@localhost ~]# awk -F: '$1 !~ /root/ {i=1;while(i<=NF){printf $i; printf " ";i+=2};printf "\n"}' /etc/passwd
while循环打印出奇数列(字段)的值
[root@localhost ~]# awk -F: '{for(i=1;i<NF;i+=2) { printf $i;printf " ";};printf "\n"}' /etc/passwd
for循环打印出奇数列(字段)的值
[root@localhost ~]# awk -F: '{for(i=2;i<NF;i+=2) { printf $i;printf " ";};printf "\n"}' /etc/passwd
for循环打印偶数列(字段)的值
内置变量
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命令的参数的个数
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... 数组变量前要加美元符$
awk 中数组下标为 任意字符串(当然也可以使用数值来引用,但使用什么得自己去定义) 数组变量前不需要加美元符$
[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 ~]#
[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
[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
[root@localhost ~]# awk -F: '$NF !~ /^$/{SHELL[$NF]++}END{for(A in SHELL) print A,SHELL[A]}' /etc/passwd
看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]}'
# netstat -ant