awk命令介绍和常见使用方法

awk、sed、grep这三个命令并称为文本处理三剑客,但是awk的功能远远多出其他两个命令很多。最初由贝尔实验室研制。后来GUN组织在awk的基础上研制了gawk,现在我们在Linux使用的一般都是gawk这个命令,但是为了一些习惯,将awk作为gawk的链接,也就是说,现在在bash中使用awk还是使用gawk都是一样的。接下来为了方便,直接称之为awk。

那么awk到底好在哪里呢?它的好处是在于使用这个命令可以进行简单的编程,在使用别的命令的时候需要写一个脚本才能实现的功能,使用这个命令就可以直接实现。下面简单的介绍这个命令的格式:

    awk [options] 'program' file...

program部分可以是: pattern{action statement;...}

 pattern部分可以是:BEGIN,END,用来决定动作语句何时触发及通过什么事件触发,比如如果这里是“BEGIN”那么就是在这个命令执行之前执行,同理,“END”是在这个命令执行完毕后执行。“BEGIN”和“END0”都是可以选择的,没有也可以;

 action statement 部分可以是:print,printf,它们是对数据进行处理的语句,通常放在一对{}之中,决定着在执行这个命令之后产生的数据如何的表达。

  在使用awk对数据进行处理时,会根据特定的标识对数据进行分段,这种特定标识就是分隔符,默认是空白字符,可以通过“-F”来进行指定。经过分隔符分隔之后的每一个小分段,都称为一个分段(Field);默认awk会使用内置位置变量来存储各个字段的值;这些变量就是$1,$2,$3,...$N;由换行符分隔的数据中的每一行,就是一个记录;在awk处理数据的时候,使用$0保存整行的内容。

    常用选项

-F:用来指明此次数据处理的字段分隔符,默认是空白分隔符

-v:var=value:用于自定义变量和为自定义变量赋初始值

对于变量,我们可以自己定义,也可以使用命令自己的变量,命令自己的变量有很多,比如:

    FS:input field seperator,输入字段分隔符,默认空白字符

示例:

1
~]# awk -v FS=':' '{print $1}' /etc/passwd

OFS:outpit field seperator,输入字段分隔符,默认空白字符

示例:

1
~]# awk -v FS=':' -v OFS=':' '{print $1 $3}' /etc/passwd

RS:input record seperator,输入记录分隔符,默认换行符;

注意:即使指定了新的输入记录分隔符,原换行符仍然有效

示例:

1
~]# awk -v RS='/' '{print $0}' /etc/passwd

ORS:output record seperator,输出记录分隔符


NF:number of field,字段数量

(不加$输出这个变量的值,加上$输出最后一个字段)

示例:

1
2
3
~]# awk -v FS=':' '{print NF}' /etc/passwd
~]# awk -v FS=':' '{print $NF}' /etc/passwd
~]# awk -v FS=':' '{print $(NF-1)}' /etc/passwd

NR:number of record,行数;鉴于awk遍历文件每行的特性,可以将该变量理解为行号

示例:

1
~]# awk '{print NR}' /etc/passwd    #(如果同时输出多个文件,那么行数会累加)

FNR:file number of record,分别统计各个文件的行数,行号

示例:

1
~]# awk '{print FNR}' /etc/passwd

FILENAME:输出当前正在处理的文件的文件名;

示例:

1
~]# awk '{print FILENAME}' /etc/passwd

ARGC:argument count,整个命令行中的参数的数量,包括命令本身算一个

示例:

1
~]# awk '{print ARGC}' /etc/passwd #(输出结果为2,awk '{print ARGC}'是1,/etc/passwd是2)

ARGV:数组,argument value,保存了命令行中各个参数的具体内容

示例:

1
~]# awk '{print ARGV[1]}' /etc/passwd #(输出结果为awk)

   还可以自己定义变量,定义的方法如下:

-v var=value

     注意:变量名区分字符大小写

示例:

1
~]# awk -v var1='hello' -F: '{print var1 ,$1}' /etc/passwd

  除了变量,还可以定义数组:array[index_expression]

index_expression:

 1) 可以使用任意的字符串,字符串必须使用双引号;

 2) 如果某数组元素事先不存在,当引用该元素时,awk会自动创建此元素,并且为该元素赋"空字符串"作为其初始值;

注意:如果想要判断数组中某个元素是否存在,一般会使用"index in array"格式进行;

示例:

1
~]# awk 'BEGIN{name["leader"]="zhang";name["mem1"]="li";name["mem2"]="wang";print name["leader"]}'

  在这个命令中,变量是一个很重要也很有意义的东西,配合变量使用的就是如何将其输出,在上面的例子中,使用到了print,这个选项是将一些内容进行输出,可以是一些变量,或者是一些自己想要输出的字符串,比如:

1
awk '{print "aaaaaaaaaa" $1}' /etc/fstab


  上面这条命令就是取出“/etc/fstab”中的每一行的第一列进行输出,并且在输出的时候前面加上一串a,使用这种方法我们可以对输出内容进行控制。但是这种方法输出的格式可能并不美观。所以就用到了另外一种命令,叫做“printf”选项,这个选项可以对输出的格式进行控制,效果如同C语言中的那个“printf”。

    printf选项:

格式化输出命令:printf "FORMAT" item1,item2,...

要点:

      1)必须给出合适的FORMAT(显示的格式)

2)默认不自动换行,需要显式给出换行控制符(\n)

3)FORMAT中需要为后面的每一个item指定一个格式符

 

格式符可以有以下几种,选择了一种,就会将后边对应的“item”语句按照这种格式进行输出:

%c:显示字符的ASCII码

%d,%i:显示十进制整数

%f:显示浮点数字

%e,%E:使用科学计数法显示数字

%g,%G:使用科学计数法显示浮点数字

%s:显示字符串

%u:(unsigned)显示无符号整数

%%:显示%自身


修饰符:

#[.#]:第一个数字用来控制显示宽度;第二个数字表示小数点的精度(第二个数可以省略)

例如:%3.1f %5s

-:表示采用左对齐机制;默认是右对齐; %-15s

+:显示数字的正负符号; %+d


示例:

1
awk -F: '{printf "%20s: %-5s\n",$1,$3}' /etc/passwd


  在进行输出的时候还可以进行运算,可以使用一些运算符来到这个目的:

算数操作符:

     x+y,x-y,x*y,x/y,x^y,x%y

-x:将正数转换为负数

+x:将字符串转换为数值

       示例:

1
awk 'BEGIN{print 1+2}'

字符串操作符:

没有符号的操作符,表示字符串连接之意

赋值操作符:

=,+=,-=,*=,/=,%=,^=

++,--

比较操作符:

>,>=,<,<=,==,!=

        示例:

1
awk -F: '$3==1000{print $0}' /etc/passwd

模式匹配操作符

~:左侧的字符串是否能够被右侧的模式所匹配

!~:左侧的字符串是否不能够被右侧的模式所匹配

  示例:

1
awk -F: '$NF~/bash/{print $0}' /etc/passwd


逻辑操作符:

&&:与

||:或

示例:

1
awk -F: '$3<=1000&&$3>=500{print $0}' /etc/passwd #显示UID在用户500-1000之间的

条件表达式:

condition(selector)?if-true-expression:if-false-expression

        (首先写判断条件,然后使用一个“?”进行分隔,后边紧跟的是如果前边的判断条件成立所执行的命令,再然后使用“:”进行分隔,后跟如果判断条件不符合所执行的命令)

示例:

1
2
awk -F: '{$3>=1000?usertype="a":usertype="b";printf "%-20s: %-20s\n",usertype,$1}' /etc/passwd
awk -F: '{$3>=1000?usertype="a":usertype="b";print usertype,$1}' /etc/passwd




  这个命令的强大之处还在于它可以达到grep和sed的效果,比如使用匹配模式就可以实现grep的效果:

  在上面的命令格式中可以看到有PATTERN这么一个选项,它可以是以下五种:

1)empty:空模式,处理文件中的每一行

2)[!]/REGEXP/:仅处理[不]能被PATTERN匹配到的行

示例:

1
~]# awk '[!]/^r/{print}' /etc/passwd

3)关系表达式:$3>=1000或者$NF~/bash/

4)行的范围

/regexp1/,/regexp2/:从被regexp1匹配的这一行开始到被regexp2匹配的这一行结束,有多少这一类匹配结果,就显示多少次

示例:

1
~]# awk '/^r/,/^a/{print}' /etc/passwd #这个命令的功能是匹配所有从以r开头的行到以a开头的行

5)BEGIN/END模式:

BEGIN{}:仅在开始处理文件中的第一行文本之前执行一次的语句块

示例:

1
~]# awk -F: 'BEGIN{printf "%20s %5s\n","Username","UserID"}{printf "%20s %5s\n",$1,$3}' /etc/passwd

注意:在输出特定格式的表头时,常用此语句块;

END{}:仅在文本处理完成但命令尚未退出时执行一次的语句块

示例:

1
~]# awk -F: 'BEGIN{printf "%20s %5s\n","Username","UserID"}{printf "%20s %5s\n",$1,$3}END{print "========================\n",NR " users"}' /etc/passwd



   除了能够进行匹配之外,还可以实现其他语言中的控制语句,比如:

1) if-else:

语法:if (condition) {statement} [ else {statement} ]

使用场景:对awk取得的整行或某个字段做条件判断;

示例:

1
~]# awk -F: '{if($3>=1000) {print $1} else {print $1,$3}}' /etc/passwd

2) while循环:条件为真,进入循环;条件为假,退出循环;

语法:while (condition) statement

使用场景:对一行内的多个字段逐一做类似的处理;对数组中各个元素遍历及处理;

示例:

1
~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {printf "%s: %d\n",$i,length($i);i++}}' /etc/grub2.cfg

3) do...while循环:

语法:do statement while (condition)

意义:同while循环,但至少执行一次循环体中的语句;


4) for循环:

语法:for (expr1; expr2; expr3) statement

expr1:变量赋初值;

expr2:条件判断;

expr3:变量值的递增或递减调整;

示例:

1
~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {printf "%s: %d\n",$i,length($i)}}' /etc/grub2.cfg

        或者配合数组来查看已连接状态下,同一客户端的连接数量:

1
~]# ss -tn | awk '/^ESTAB\>/{print $NF}' | awk -F: '{state[$1]++}END{for(s in state){print state[s],s}}'


    5) break 和 continue

break [n]:跳出循环,后头跟上哪个数字就跳出几层循环

continue:跳过本次循环,直接进入下次循环;


6) next语句:

提前结束对本行的处理,而直接进入下一行;

示例:

1
~]# awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd



  在使用控制语句进行简单编程的时候还可以使用函数,函数也分为命令内置函数和自建函数。内置函数常见的有以下两个:

    length(string):计算字符串长度

split(string,array[,fieldsep])


示例:

1
~]# awk '{print sdasdas $1 length($1)}' /etc/fstab
1
~]# awk '{split($0,user,":");print user[1]}' /etc/passwd














本文转自正经的青年51CTO博客,原文链接: http://blog.51cto.com/11142243/1957568,如需转载请自行联系原作者



上一篇:小程序微信支付C#


下一篇:个人微信公众号,每天推送一篇高质量文章