awk是linux上非常好用的文本处理工具,对比sed命令常用语一整行的处理,awk常用于列的处理,比如打印指定行的第3列。本文通过awk命令常用实例来描述awk命令的使用方法。
awk基本语法
awk [ -F 分隔符] '条件类型1{动作1} 条件类型2{动作2}...' input-file
说明:
(1)-F表示设置分隔符,默认为空格。条件类型表示针对每行的匹配条件,可以是条件语句、复合语句或正则表达式,动作表示执行的命令,命令必须放在大括号{}内
(2)任何awk语句都由模式和动作组成。
(3)操作命令是否执行与匹配条件是否匹配相关。如果匹配,则执行对应的命令,不匹配,则不执行。
(4)模式是否设置是可选的。如果模式不设置,则对所有每一行行执行命令。
(5)$0表示行,$1、$2、$3...$n分别表示第1列、第2列、第3列...第n列。
awk处理流程:
(1)读入第1行,并将第1行的数据填入$0、$1、$2、$3等变量中;
(2)根据条件类型的限制,判断是否需要执行后面的动作。直到做完所有的动作和条件类型。
(3)每一行重复步骤(1)和(2),直到文件所有行全部处理完成。
简单例子,假设servers.txt文件内容如下
1:192.168.0.1:root:root 2:192.168.0.2:oracle:oracle 3:192.168.0.3:admin:admin
打印文件中第2、3、4列内容。awk命令如下:
awk -F ':' '{print $2,$3,$4}' services.txt
说明:-F ':'表示以":"冒号作为分隔符,print $2,$3,$4表示打印第2/3/4列。如果需要设置多个分隔符。可以用-F '[分隔符1 分隔符2...]',如-F '[:/]'表示同时以:冒号和/反斜杠作为分隔符。
awk中正则表达式与条件操作符
awk中正则表达式匹配操作中经常用到字符如下:
. * + ? $ | \ [] {} ()
条件操作符如下:
<(小于) <=(小于等于) ==(等于) >(大于) >=(大于等于) !=(不等于) ~(匹配正则表达式) !~(不匹配正则表达式)
其中<、>、<=等操作符用法比较直观,这里主要讲~(匹配正则表达式)、 !~(不匹配正则表达式)两个表达式的用法。
基本实例如下:
(1)打印第1个字段包含root字符串的行
awk -F":" '{if($1~/root/)print $0}' /etc/passwd #写法一 awk -F":" '$1~/root/{print $0}' /etc/passwd #写法二
(2)打印第1个字段不包含root字符串的行
awk -F":" '{if($1 !~ /root/)print $0}' /etc/passwd #写法一 awk -F":" '$1 !~ /root/{print $0}' /etc/passwd #写法二
(3)打印第1个字段等于root字符串的行
awk -F":" '{if($1 == 'root')print $0}' /etc/passwd #写法一 awk -F":" '$1 == 'root'{print $0}' /etc/passwd #写法二
(4)打印第1个字段不等于root字符串的行
awk -F":" '{if($1 != 'root')print $0}' /etc/passwd #写法一 awk -F":" '$1 != 'root'{print $0}' /etc/passwd #写法二
(5)打印用户ID小于500的用户
awk -F":" '{if($2<500)print $0}' /etc/passwd
(6)打印行首为oracle的行
awk -F":" '{if($1~/^oracle/)print $0}' /etc/passwd
(7)打印匹配oracle或者root字符串的行
awk -F":" '{if($1~/(root|oracle)/)print $0}' /etc/passwd #用正则表达式元字符|的方式 awk -F":" '{if($1~/root/ || $1~/oracle/)print $0}' /etc/passwd #用或||的方式
说明:竖线符"|"表示匹配竖线"|"两边模式之一。使用竖线符时,语句必须用圆括号()括起来。
(8)打印同时匹配oracle和root的行
awk '{if($1=='root' && $2=='500')print $0}' /etc/passwd
awk内置变量
awk的内置变量包括FS、NF、OFS、ORS、NR等内容,下面逐一列举其含义和用法。
(1)FS 表示用于设置列的分隔符,与-F选项功能相同。缺省情况下为空格。举例如下:
echo "2017-12-20" |awk 'BEGIN{FS="-"}{print $1,$2,$3}' #输出2017 12 20
(2)NF 表示一行记录列的总数。如果需要打印最后一列内容,举例如下:
echo "/usr/local/bin/python" | awk -F '/' '{print $NF}' #输出python
说明:NF常用于打印倒数指定列的内容。
(3)OFS 表示指定输出字段分隔符,缺省为空格。举例如下:
echo "1990 09 09" | awk 'BEGIN{OFS="-"}{print $1,$2,$3}' #输出1990-09-09
(4)ORS 表示输出行记录的分隔符,默认为换行符(\n)。如果需要设置输出行的分隔符为#,可以如下表示:
echo -e "1990\n09\n09" | awk 'BEGIN{ORS="#"}{print $0}' #输出1990#09#09#
(5)NR 表示已读的记录数。如果需要打印文件行数,举例如下:
awk 'END{print NR}' /etc/passwd
awk内置字符串函数
(1)length(string) 表示计算字符串string的长度,返回值为字符串长度。举例如下:
echo "Hello World" | awk '{print length($0)}' #输出11
(2)index(string,substr) 表示在字符串string中待查找字符substr的位置,其中substr必须用双引号将字符串括起来。举例如下:
echo "Hello World" | awk '{print index($0,"o")}' #输出5 awk 'BEGIN{print index("Hello World","o")}' #输出5
(3)match(string,regex) 测试字符串string中是否包含匹配正则表达式regex的字符串,返回值为成功出现的字符排列数,如果未找到,返回0。举例如下:
awk 'BEGIN{print match("Hello World",'o')}' #查找字符串o第一次出现的位置,输出1 echo "Hello World" | awk '{print match($0,'o')}' #同上,输出1 awk 'BEGIN{print match("Hello World",/[Oo]/)}' #查找字符串大写或小写o第一次出现的位置。输出5
(4)split(string,arr,fs) 表示使用指定的分隔符fs将字符串string进行分隔,分割出的结果保存到arr数组。split()函数返回值为数组长度。举例如下:
echo "123#456#789" | awk '{len=split($0,arr,"#");for(i=1;i<=len;i++)print arr[i]}'
说明:通过获取到的数组长度,通过循环方式获取数组中的内容,其中数组下标是从1开始计算。
(5)sub(regex,string) 表示用字符串string替换正则表达式regex匹配的内容。举例如下:
echo "Java:Python:Java:C" | awk 'sub(/Java/,"Ruby",$0)' #输出Ruby:Python:Java:C
(6)substr(string,pos) 获取字符串sting中从指定位置pos后的内容。举例如下
echo "Java:Python:C" | awk '{print substr($0,1,4)}' #输出Java
(7)substr(string,pos,n) 获取字符串string中从指定位置pos开始长度为n的内容
echo "Java:Python:C" | awk '{print substr($0,6)}' #输出Python:C
(8)gsub(regex,string) 表示使用字符串string替换正则表达式regex匹配的内容。举例如下:
echo "Java:Python:Java:C" | awk 'gsub(/Java/,"Ruby")' #输出Ruby:Python:Ruby:C
(9)gsub(regex,string,target) 表示在指定的范围内,使用字符串string替换正则表达式regex匹配的内容。举例如下:
echo "Learn Shell at 2013-08-08" | awk 'gsub(/-/,":",$4)' #输出Learn Shell at 2013:08:08
总结
本文内容介绍了awk命令的基本语法和常用实例。awk具有强大的文本处理能力,掌握awk命令的基本内容可以完成工作上遇到的大部分问题。另外,awk构造大批量测试数据有非常高的效率。