awk 数组回顾: 9.1 数组 举例:统计当前主机上每一个TCP连接状态以及每种连接状态的数目【非常实用】 # netstat -tan | awk '/^tcp/{STATE[$NF]++}END{for (S in STATE) {print S,STATE[S]}}' 注:单引号内的都是PARTTEN,此句没有ACTION【定义数组、变量尽量大写,小写也不错】 LISTEN 11 ESTABLISHED 1 解释: 最后一列元素$NF作为数组的下标,数组的元素是数字 array[index-expression] index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array的方式。 要遍历数组中的每一个元素,需要使用如下的特殊结构: for (var in array) { statement1, ... } 其中,var用于引用数组下标,而不是元素值; 例子: netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引; awk '{counts[$1]++}; END {for(url in counts) print counts[url], url}' /var/log/httpd/access_log 用法与上一个例子相同,用于统计某日志文件中IP地的访问量 [root@master interview]# cat b.txt 001 wodi 12k 002 yingsui 15k 003 jeacen 10k 004 yideng 10k 005 kuqi 8k 006 xiaofen 6k 007 wodi 11k 008 yingsui 12k 009 jeacen 4k 010 kuqi 12k 011 yideng 11k 012 xiaofen 10k awk 什么时候用变量,什么时候用数组: 如上题目:计算每个人的总工资和平均工资,如有相同的行,变量无法把多行相同元素分类累加,故用数组完成 答案:[root@xuegod68 mnt]# awk '{array[$2]+=$3;count[$2]++}END{for(key in array) print key,array[key]"k",array[key]/count[key]}' 3.txt kuqi 20k 10 jeacen 14k 7 yingsui 27k 13.5 xiaofen 16k 8 wodi 23k 11.5 yideng 21k 10.5 如下题目:求出最后一列的均值,因为每行都相同, [root@master interview]# cat a.txt asd ioq pas sqw zxs 11 asd ioq pas sqw zxz 22 asd ioq pas sqw zxw 33 asd ioq pas sqw zxd 44 asd ioq pas sqw zxe 55 答案: [root@master interview]# awk '{sum+=$6}END{print sum/NR}' a.txt 33 命令解析: [root@master interview]# grep -v "^$" b.txt |awk '{a[$2]+=$3;count[$2]++}END{print a["wodi"]}' a[$2] :代表数组元素a[wodi]的值,初值为空,第一行执行后: a[wodi] = 空 + 12 count[$2]++ : 第一行执行后,count[wodi]初始为空,count[wodi]这个元素的值自加1 [root@master interview]# netstat -ant|awk '{A[$NF]++}END{for (key in A)print key,A[key]}' TIME_WAIT 2 CLOSE_WAIT 2 established) 1 SYN_SENT 2 State 1 ESTABLISHED 13 LISTEN 45 例题:统计下面两个文件中,每行出现的频率: [root@master interview]# cat c.txt aaa bbb ccc aaa ddd aaa bbb [root@master interview]# cat d.txt aaa bbb ccc aaa ddd aaa bbb awk '{A[$1]++}END{for (key in A) print key,A[key]}' c.txt d.txt 例题:统计文件中的URL [root@master test]# cat a.txt http://www.baidu.com/index.html http://www.163.com/1.html http://www.cnblogs.com/index.html http://www.cnblogs.com/index.html http://www.cnblogs.com/index.html http://www.cnblogs.com/index.html http://www.baidu.com/2.html http://www.163.com/index.html http://www.qq.com/index.html http://www.baidu.com/3.html http://www.163.com/2.html http://www.163.com/2.html http://www.baidu.com/2.html http://www.baidu.com/2.html http://www.baidu.com/2.html [root@master test]# cat a.txt| sort |uniq -c|sort -rn # 第一个sort把相同的行放一起,uniq合并相同的行并输出重复的次数 4 http://www.cnblogs.com/index.html 4 http://www.baidu.com/2.html 2 http://www.163.com/2.html 1 http://www.qq.com/index.html 1 http://www.baidu.com/index.html 1 http://www.baidu.com/3.html 1 http://www.163.com/index.html 1 http://www.163.com/1.html awk方法1:$0代表整行; array[1]为split函数分割结果的第一个部分,array[2]是域名,array[3]是uri 。 [root@master test]# awk '{split($0,array,"/+");var=array[2];count[var]++}END{for (k in count)print k,count[k]}' a.txt www.qq.com 1 www.cnblogs.com 4 www.baidu.com 6 www.163.com 4 awk方法2: [root@master test]# awk -F "[/]+" '{A[$2]++}END{for (k in A) print k,A[k]}' a.txt www.qq.com 1 www.cnblogs.com 4 www.baidu.com 6 www.163.com 4
awk补充:
# awk的record和field相关变量,设置指定分割符、调整分隔符: RS:Record Separator,RS是awk读取文件时的行分隔符 ORS:Output Record Separate, ORS是awk输出时的行结束符 更简单的讲,就是awk在输出时,会在每行记录后面增加一个ORS变量所设定的值。ORS的值只能设定为字符串,默认情况下,ORS的值是 FS:Field Separator,字段分隔符 OFS:Out of Field Separator,输出字段分隔符 单行单列相互转换: 方法1:awk '{print $2}' a.txt | tr ' ' ' ' 方法2:cat a.txt|xargs 多行、多列转换: name age alice 21 ryan 30 转换为: name alice ryan age 21 30 awk '{ for(i=1;i<=NF;i++){ if(NR==1){ arr[i]=$i; }else{ arr[i]=arr[i]" "$i; } } } END{ for(i=1;i<=NF;i++){ print arr[i]; } }' file.txt # 使用一维数组,记录每一列的组合串即可,当是第一行时赋值,否则都是累加,即字符串拼接。 [root@localhost ~]# cat a.txt 123 43as asd ss dd1 [root@localhost ~]# cat a.txt |awk 'BEGIN{RS=" ";ORS=" "}{print $1}END{printf " "}' # {printf " "} 结尾加个换行符 123 43as asd ss dd1 [root@localhost ~]# cat a.txt |awk 'BEGIN{ORS=" "}{print $1}END{printf " "}' | awk 'BEGIN{RS=" "}{print $1}' 123 43as asd ss dd1 示例1: 1.txt a|b|c # 单行以|分割,变为单列 awk 'BEGIN{ RS="|"; } { print $0 }' a b c FS、OFS例子: [root@localhost ~]# cat c.txt 123 123 rrr 43as qqq ttt asd aaa fff ss sss ggg dd1 ddd hhh [root@localhost ~]# cat c.txt |awk 'BEGIN{FS=" ";OFS="|"}{$1=$1;print $0}' # $1=$1,awk只有对域有了操作,如$1=$1,OFS才会生效 123|123|rrr 43as|qqq|ttt asd|aaa|fff ss|sss|ggg dd1|ddd|hhh [root@localhost ~]# cat c.txt |awk 'BEGIN{FS=" ";OFS="|"}{print $1,$2,$3}' 123|123|rrr 43as|qqq|ttt asd|aaa|fff ss|sss|ggg dd1|ddd|hhh 修改分隔符: 例中“i----love----you”,“----”为分隔符(FS),如果我们想改为用其他符号显示可以这样: awk 'BEGIN{ FS="----";OFS="*****" }{ print $1,$2,$3 }' filename i*****love*****you 在理解了 RS 和 FS 之后,我们来回顾开始的那句话:“awk是基于行列操作文本的”,这个说法实际上不是很准确,因为在改变了 RS 后,awk 中的“行”已经不是一般的“行”了 同样,改变了 FS 后,awk 中的“列”也已经不是一般的“列”了; 因此,准确的应该这样讲:“awk是基于 记录(record) 和 域(field) 操作文本的”;当对域分隔符修改后,输出时,要对域操作才能生效 综合例题: [root@localhost ~]# cat b.txt # 1 2 3 # 4 5 # 6 7 8 9 # 输出为: 123 45 6789 [root@localhost ~]# awk 'BEGIN{RS=" ";ORS=""}{print $1}' b.txt |awk 'BEGIN{RS="#"}{print $0}' |awk '{if($0!="")print}' 123 45 6789 # 过程: 这一列先转化为行:awk 'BEGIN{RS=" ";ORS=""}{print $1}' b.txt 如:#123#45#6789# 再按#,按列切割; [root@localhost ~]# awk 'BEGIN{RS=" ";ORS=""}{print $1}' b.txt |awk 'BEGIN{FS="#";OFS=" "}{$1=$1;print $0}' 123 45 6789 最后去掉空行即可; awk练习题 wang 4 cui 3 zhao 4 liu 3 liu 3 chang 5 li 2 1 通过第一个域找出字符长度为4的 2 当第二列值大于3时,创建空白文件,文件名为当前行第一个域$1 (touch $1) 3 将文档中 liu 字符串替换为 hong 4 求第二列的和 5 求第二列的平均值 6 求第二列中的最大值 7 将第一列过滤重复后,列出每一项,每一项的出现次数,每一项的大小总和 1、字符串长度 awk 'length($1)=="4"{print $1}' 2、执行系统命令 awk '{if($2>3){system ("touch "$1)}}' 3、gsub(/r/,"s",域) 在指定域(默认$0)中用s替代r (sed 's///g') awk '{gsub(/liu/,"hong",$1);print $0}' a.txt 4、列求和 df -h | awk '{a+=$2}END{print a}' 5、列求平均值 df -h | awk '{a+=$2}END{print a/NR}' df -h | awk '{a+=$2;b++}END{print a,a/b}' 6、列求最大值 df -h | awk 'BEGIN{a=0}{if($2>a) a=$2 }END{print a}' 7、将第一列过滤重复列出每一项,每一项的出现次数,每一项的大小总和 首先定义一个数组记录重复项:A[$1]++ 再定义一个数组做重复项对应值的累加和;B[$1]+=$2 [root@localhost ~]# cat a.txt |awk '{A[$1]++;B[$1]+=$2}END{for (i in A)print i,A[i],B[i]}' cui 1 3 chang 1 5 li 1 2 wang 1 4 zhao 1 4 liu 2 6
xargs:
#xargs常用选项: -n: 指定一次处理的参数个数 -d: 自定义参数界定符 -p: 询问是否运行 later command 参数 -t : 表示先打印命令,然后再执行 -i : 逐项处理 # 多行变成单行 -bash-3.2# cat test.txt a b c d e f g o p q -bash-3.2# cat test.txt |xargs a b c d e f g o p q #单行变成多行 -bash-3.2# cat test.txt a b c d e f g o p q -bash-3.2# cat test.txt |xargs -n 2 a b c d e f g o p q #删除某个重复的字符来做定界符 -bash-3.2# cat test.txt Aaaagttttgyyyygcccc -bash-3.2# cat test.txt |xargs -d g aaaa tttt yyyy cccc # 将所有文件重命名,逐项处理每个参数 ls *.txt |xargs -t -i mv {} {}.bak
grep: 文本过滤器 grep 'pattern' input_file ... sed:流编辑器 awk: 报告生成器 格式化以后,显示 AWK a.k.a. Aho, Kernighan and Weinberger new awk: nawk gawk, awk # awk [options] 'script' file1 file2, ... 【从多个文件中读取文本信息,而后根据'script'(由'PATTERN { action }'组成)将其格式化为特定的格式,再显示之】 # awk [options] 'PATTERN { action }' file1 file2, ... 【只处理被PATTERN匹配到的行,action为处理动作,常见的处理动作:print简单打印,printf可以自定义显示格式】 print, printf awk常用指定分隔符的选项:-F 【默认空格分隔符】 [root@whiteskpc myscript]# cat awk.txt this is a test [root@whiteskpc myscript]# awk '{print $0}' awk.txt this is a test [root@whiteskpc myscript]# awk '{print $1}' awk.txt this [root@whiteskpc myscript]# awk '{print $4}' awk.txt test [root@whiteskpc myscript]# awk '{print $1,$4}' awk.txt this test [root@whiteskpc myscript]# awk 'BEGIN{OFS="#"} {print $1,$4}' awk.txt 【指定输出分隔符为#,注意大写】 this#test [root@whiteskpc myscript]# awk 'BEGIN{OFS=":"} {print $1,$2,$3,$4}' awk.txt 【打印整个条目,用:分隔】 this:is:a:test awk的输出: 一、print print的使用格式: print item1, item2, ... 例: [root@whiteskpc myscript]# awk 'BEGIN{OFS=":"} {print $1,"hello",$2,$3,$4}' awk.txt 【添加一个字段,把一个文本字符串单做item输出,注意双引号而非单引号】 this:hello:is:a:test 要点: 1、各项目之间使用逗号隔开,而输出时则以空白字符分隔; 2、输出的item可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出; 3、print命令后面的item可以省略,此时其功能相当于print $0, 因此,如果想输出空白行,则需要使用print ""; 例子: # awk 'BEGIN { print "line one line two line three" }' awk -F: '{ print $1, $3 }' /etc/passwd 二、awk变量 2.1 awk内置变量之记录变量: FS: field separator,读取文件本时,所使用字段分隔符; RS: Record separator,输入文本信息所使用的换行符; OFS: Output Filed Separator: ORS:Output Row Separator: awk -F: 【指定输入分隔符,读取文本的时候以什么为分隔符】 OFS="#" 【输出分隔符,打印文本时以什么为分隔符】 FS=":" 【FS也可指定输入分隔符】 2.2 awk内置变量之数据变量: NR: The number of input records,awk命令所处理的行的记录数;如果有多个文件,这个数目会把处理的多个文件中的行统一计数; NF:Number of Field,当前记录的field个数; 【统计当前正在处理的行的字段总数】 例: [root@whiteskpc myscript]# cat awk.txt this is a test [root@whiteskpc myscript]# awk '{print NF}' awk.txt 4 [root@whiteskpc myscript]# awk '{print $NF}' awk.txt 【表示打印当前行的最后一个字段】 test [root@whiteskpc myscript]# awk '{print NR}' awk.txt 1 FNR:facing number of input records 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数; ARGV: 数组,保存命令行本身这个字符串,如awk '{print $0}' a.txt b.txt这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt; ARGC: awk命令的参数的个数; FILENAME: awk命令所处理的文件的名称; ENVIRON:当前shell环境变量及其值的关联数组; 如:awk 'BEGIN{print ENVIRON["PATH"]}' 说明: awk处理两个文件,第一个文件处理了100行,第二个文件处理了20行:则NR=121,FNR=21 即:NR是指对读取处理的所有文件,处理了多少行。 【绝对计数】 FNR是指对于当前正在处理的文件(不考虑其他文件),在多少行。 【各自计数】 例: [root@whiteskpc myscript]# cat awk.txt this is a test this is a test [root@whiteskpc myscript]# cat awk.txt >> awk1.txt [root@whiteskpc myscript]# cat awk1.txt this is a test this is a test this is a test this is a test [root@whiteskpc myscript]# awk '{print NR}' awk.txt 1 2 [root@whiteskpc myscript]# awk '{print NR}' awk.txt awk1.txt 1 2 3 4 5 6 [root@whiteskpc myscript]# awk '{print FNR}' awk.txt awk1.txt 1 2 1 2 3 4 2.3 用户自定义变量 gawk允许用户自定义自己的变量以便在程序代码中使用,变量名命名规则与大多数编程语言相同,只能使用字母、数字和下划线,且不能以数字开头。gawk变量名称区分字符大小写。 变量赋值两种方式: 【脚本中赋值变量,BEGIN模式;命令航中赋值变量awk -v】 2.3.1 在脚本中赋值变量 在gawk中给变量赋值使用赋值语句进行,例如: awk 'BEGIN{var="variable testing";print var}' 【action中如果有多个语句,语句之间用分号隔开】 2.3.2 在命令行中使用赋值变量 gawk命令也可以在“脚本”外为变量赋值,并在脚本中进行引用。例如,上述的例子还可以改写为: awk -v var="variable testing" 'BEGIN{print var}' 【awk -v,variable ,表示-v后面跟了个变量名,而后给变量赋值,awk后面不带文件通常使用BEGIN模式】 注意:在awk中打印变量值是不需要加$符号的,这点和bash不同!其实,加了$符号表示打印字段。 三、printf printf命令的使用格式: printf format, item1, item2, ... 要点: 1、其与print命令的最大不同是,printf需要指定format; 2、format用于指定后面的每个item的输出格式; 3、printf语句不会自动打印换行符; 【和print的区别】 format格式的指示符都以%开头,后跟一个字符;如下: 【格式指示符与格式指示符之间不需要使用逗号或其他符号分隔】 %c: 显示字符的ASCII码; %d, %i:十进制整数; %e, %E:科学计数法显示数值; %f: 显示浮点数; %g, %G: 以科学计数法的格式或浮点数的格式显示数值; %s: 显示字符串; %u: 无符号整数; %%: 显示%自身; 修饰符: 【修饰符加在%和字母之间】 N: 显示宽度; -: 左对齐; 【不加-表示右对齐】 +:显示数值符号; printf用法例子: [root@whiteskpc myscript]# cat awk.txt this is a test [root@whiteskpc myscript]# awk '{printf "%s ",$1}' awk.txt this [root@whiteskpc myscript]# awk '{printf "%10s ",$1}' awk.txt 【N=10,宽度10个字符,没有字符的用空白字符补齐】 this [root@whiteskpc myscript]# awk '{printf "%-10s ",$1}' awk.txt 【左对齐,this右边有十个空白字符】 this [root@whiteskpc myscript]# awk '{printf "%-10s,%-10s ",$1,$3}' awk.txt 【显示两个字段方法】 this ,a [root@whiteskpc myscript]# awk '{printf "%-10s%-10s ",$1,$3}' awk.txt 【格式指示符与格式指示符之间不需要使用逗号或其他符号分隔】 this a [root@whiteskpc myscript]# awk '{printf "%-10s %-10s ",$1,$3}' awk.txt this a 以科学计数法显示每个用户的ID号码: # awk -F: '{printf "%-5d ",$3}' /etc/passwd 【左对齐】 # awk -F: '{printf "%-15s %i ",$1,$3}' /etc/passwd 四、输出重定向 print items > output-file print items >> output-file print items | command 特殊文件描述符: /dev/stdin:标准输入 /dev/sdtout: 标准输出 /dev/stderr: 错误输出 /dev/fd/N: 某特定文件描述符,如/dev/stdin就相当于/dev/fd/0; 例子: # awk -F: '{printf "%-15s %i ",$1,$3 > "/dev/stderr" }' /etc/passwd 六、awk的操作符: 6.1 算术操作符: -x: 负值 +x: 转换为数值; x^y: x**y: 次方 x*y: 乘法 x/y:除法 x+y: x-y: x%y: 6.2 字符串操作符: 只有一个,而且不用写出来,用于实现字符串连接; 6.3 赋值操作符: = += -= *= /= %= ^= **= ++ -- 需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代; 6.4 布尔值 awk中,任何非0值或非空字符串都为真,反之就为假; 6.5 比较操作符: x < y True if x is less than y. x <= y True if x is less than or equal to y. x > y True if x is greater than y. x >= y True if x is greater than or equal to y. x == y True if x is equal to y. x != y True if x is not equal to y. x ~ y True if the string x matches the regexp denoted by y. 【y代表正则表达式模式PATTERN,x字符串能被模式y匹配到则为真,否则为假】 x !~ y True if the string x does not match the regexp denoted by y. subscript in array True if the array array has an element with the subscript subscript.【在指定的数组中有此元素下标,则为真,否则为假】 6.7 表达式间的逻辑关系符: && || 6.8 条件表达式: selector?if-true-exp:if-false-exp 相当于: if selector; then if-true-exp else if-false-exp fi 举例: a=3 b=4 a>b?a is max:b ia max 6.9 函数调用: function_name (para1,para2) 、 awk格式回顾: awk [options] 'PATTERN { action }' file1 file2, ... 七 awk的模式: awk 'program' input-file1 input-file2 ... 其中的program为: pattern { action } pattern { action } ... 7.1 常见的模式类型: 1、Regexp: 正则表达式,格式为/regular expression/ 2、expresssion: 表达式,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu",用运算符~(匹配)和!~(不匹配)。【各种逻辑表达式都可以应用】 3、Ranges: 指定的匹配范围,格式为pat1,pat2 4、BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次 5、Empty(空模式):匹配任意输入行; 1、Regexp: 正则表达式,格式为/regular expression/ 例:只处理/etc/passwd中以r开头的用户名:# awk -F: '/^r/{print $1}' /etc/passwd root rpc rpcuser 2、expresssion: 表达式,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu",用运算符~(匹配)和!~(不匹配)。【各种逻辑表达式都可以应用】 例: 查看剩余内存: free -m|awk 'NR==3{print $NF}' 显示用户ID大于500的用户名和ID号:# awk -F: '$3>=500{print $1,$3}' /etc/passwd nfsnobody 65534 whitesky 500 hadoop 501 whitesmb 502 扩展: [root@whiteskpc myscript]# awk -F: '$3-1>=500{print $1,$3}' /etc/passwd 【由此可知,直接使用算术运算来比较也完全可以,只要表达式支持的都可以】 nfsnobody 65534 hadoop 501 whitesmb 502 例:显示默认shell为bash的用户: # awk -F: '/bash$/{print $1,$7}' /etc/passwd【# awk -F: '$7~"bash$"{print $1,$7}' /etc/passwd ,此种写法也可】 root /bin/bash whitesky /bin/bash hadoop /bin/bash whitesmb /bin/bash mysql /bin/bash 非bash的用户:# awk -F: '$7!~"bash$"{print $1,$7}' /etc/passwd 3、Ranges: 指定的匹配范围,格式为pat1,pat2 例: [root@whiteskpc myscript]# awk -F: '$3==0,$7~"nologin"{print $1,$3,$7}' /etc/passwd root 0 /bin/bash bin 1 /sbin/nologin 4、BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次 例: 在awk执行之前加一个标题 # awk -F: 'BEGIN{print "Username ID Shell"}{printf "%-10s%-10s%-20s ",$1,$3,$7}' /etc/passwd 【注意BEGIN的位置】 Username ID Shell root 0 /bin/bash bin 1 /sbin/nologin daemon 2 /sbin/nologin adm 3 /sbin/nologin 结尾加标示: # awk -F: 'BEGIN{print "Username ID Shell"}END{print "end of report"}{printf "%-10s%-10s%-20s ",$1,$3,$7}' /etc/passwd 5、Empty(空模式):匹配任意输入行; # awk -F: '{printf "%-10s%-10s%-20s ",$1,$3,$7}' /etc/passwd 7.2 常见的Action 1、Expressions: 【赋值、判断等表达式】 2、Control statements 【控制语句,while 、for、do while三个循环,if、case条件判断语句,还可以自定义函数】 3、Compound statements 【复合语句】 4、Input statements 【重定向输入】 5、Output statements /正则表达式/:使用通配符的扩展集。 关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。 模式匹配表达式: 模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。 BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。 END:让用户在最后一条输入记录被读取之后发生的动作。 八 控制语句: 8.1 if-else 语法: 单分支:if (condition) {then-body} 双分支: if (condition) {then-body} else {[ else-body ]} 例子: awk -F: '{if ($1=="root") print $1, "Admin"; else print $1, "Common User"}' /etc/passwd awk -F: '{if ($1=="root") printf "%-15s: %s ", $1,"Admin"; else printf "%-15s: %s ", $1, "Common User"}' /etc/passwd 【printf 格式化打印】 awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd 【使用了空模式,不做过滤】 8.2 while 【对一个字段做单独处理,循环遍历每一个字段,意义不大】 语法: while (condition){statement1; statment2; ...} awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd 例:打印passwd中每一行中大于等于四个字符的字串: awk -F: '{i=1;while (i<=NF) { if (length($i)>=4) {print $i}; i++ }}' /etc/passwd 8.3 do-while 语法: do {statement1, statement2, ...} while (condition) awk -F: '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd 8.4 for 语法: for ( variable assignment; condition; iteration process) { statement1, statement2, ...} awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd 例:打印passwd中每一行中大于等于四个字符的字串: awk -F: '{for(i=1;i<=NF;i++) { if (length($i)>=4) {print $i}}}' /etc/passwd for循环还可以用来遍历数组元素: 语法: for (i in array) {statement1, statement2, ...} awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i ",A,BASH[A]}}' /etc/passwd 8.5 case 语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...} 8.6 break 和 continue 常用于循环或case语句中 8.7 next 提前结束对本行文本的处理,并接着处理下一行;例如,下面的命令将显示其ID号为奇数的用户: # awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd 九 awk中使用数组 9.1 数组 举例:统计当前主机上每一个TCP连接状态以及每种连接状态的数目【非常实用】 # netstat -tan | awk '/^tcp/{STATE[$NF]++}END{for (S in STATE) {print S,STATE[S]}}' 注:单引号内的都是PARTTEN,此句没有ACTION【定义数组、变量尽量大写,小写也不错】 LISTEN 11 ESTABLISHED 1 解释: 最后一列元素$NF作为数组的下标,数组的元素是数字 array[index-expression] index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array的方式。 要遍历数组中的每一个元素,需要使用如下的特殊结构: for (var in array) { statement1, ... } 其中,var用于引用数组下标,而不是元素值; 例子: netstat -ant | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 每出现一被/^tcp/模式匹配到的行,数组S[$NF]就加1,NF为当前匹配到的行的最后一个字段,此处用其值做为数组S的元素索引; awk '{counts[$1]++}; END {for(url in counts) print counts[url], url}' /var/log/httpd/access_log 用法与上一个例子相同,用于统计某日志文件中IP地的访问量 9.2 删除数组变量 从关系数组中删除数组索引需要使用delete命令。使用格式为: delete array[index] 十、awk的内置函数 split(string, array [, fieldsep [, seps ] ]) 功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从0开始的序列; 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个;start从1开始计数; system(command) 功能:执行系统command并将结果返回至awk命令 systime() 功能:取系统当前时间 tolower(s) 功能:将s中的所有字母转为小写 toupper(s) 功能:将s中的所有字母转为大写 十一、用户自定义函数 自定义函数使用function关键字。格式如下: function F_NAME([variable]) { statements } 函数还可以使用return语句返回值,格式为“return value”。