目录
简介 1
命令格式&说明 2
调用方法 3
域切分&操作 3
正则匹配 4
内置变量&操作 5
内置函数&操作 6
格式化输出 7
数组 8
条件判断&流程控制 9
与shell交互 10
awk与变量 10
错误排查 11
其他 11
AWK: 三位创造者Aho、Weinberger和Kernighan统称 |
官方定义:一个优秀的样式扫描与处理工具 定位:AWK 是一种用于处理文本的编程语言工具,主要用于格式化报文或从一个大的文本文件中抽取数据。提取原来文本中行的某些域进行计算组合显示,出结果
【扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行, 直到文件末尾】
[Shell过滤工具中最难掌握的,语法复杂,错误提示不明确]
优点: 1.处理文件中的记录(与数据库相比) 2.简单,解释执行,不必编译(与C相比) 3.容易获得,unix自带(whereis awk) |
模式和动作 模式部分决定了动作语句何时触发及触发的事件【处理语句】 模式部分可省略,则动作对每一行执行;模式部分可以是任何条件语句、复合语句、正则表达式 |
命令格式及说明
格式: |
语法组成:【查找 -à 执行处理】 awk ‘pattern{action}’ filename 【注意,pattern在非括号中,用于查询筛选匹配行,action在括号中,action 是在找到匹配内容时所执行的一系列命令,用于对筛选后的内容进行处理】
其中action内容可扩充,也可以有多个action。 格式: awk [ -F re] [parameter...] ['prog'] [-f progfile] |
参数说明: |
|
-F re |
允许awk更改其字段分隔符,默认空格 A.-F参数后紧跟单个分隔符,则用双引号“”,例如 –F”+” |
parameter |
该参数帮助为不同的变量赋值 |
'prog' |
awk的程序语句段。这个语句段必须用单拓号:'和'括起,以防被shell解释 |
-f progfile |
允许awk调用并执行progfile指定有程序文件 progfile是一个文本文件,他必须符合awk的语法 |
in_file |
awk的输入文件,awk允许对多个输入文件进行处理。 值得注意的是awk不修改输入文件。 如果未指定输入文件,awk将接受标准输入,并将结果显示在标准输出上。 awk支持输入输出重定向。 |
BEGIN{….} {…..} END{……} |
1 位置:’{}’ 2 作用:BEGIN和END的作用是给程序赋予初始状态和在程序结束之后执行一些扫尾的工作 BEGIN{}:awk开始扫描输入之前执行 (显示变量和预置(初始化)变量 ) END{}:在扫描完全部的输入之后执行 (最终结果 ) {}:操作
BEGIN部分:设置计数和打印头 END部分:打印输出文本总数及结尾状态标识 |
调用方法
调用方式: |
|
1 |
命令行; 普通UNIX命令 ,用于解决简单的问题 |
2 |
利用命令解释器调用awk程序; 写入脚本文件,并在首行加入#!/bin/awk –f ,执行之 |
3 |
使用-f选项调用awk程序 所有awk插入一个单独文件然后调用 awk –f awk-script-file input-files |
域的切分: |
A#B#C#D 分隔符为#,则 $1:A $2:B ……注意,所有域为 $0 【print隶属于action,所以一定要放在{}中】
awk中,缺省的情况下总是将文本文件中的一行视为一个记录,而将一行中的某一部分作为记录中的一个字段。用$1,$2,$3...这样的方式来顺序地表示行(记录)中的不同字段,$0表示整个行(记录) |
示例: |
1. 打印所有行 awk ‘{print $0}’ data.txt 2. 打印所有第二个字段 awk ‘{print $2}’ data.txt 3. 打印第一列和最后一列,并且中间有分隔符 awk ‘{print $1,$NF}’ data.txt 4. 打印行号,第一列和最后一列,中间无分隔符 awk ‘{print NR $1 $NF}’ data.txt 5. 打印包含报头 awk ‘BEGIN{print “NAME AGE”}{print $1,$7}’ data.txt 6. 打印包含尾部 awk ‘BEGIN{print “NAME AGE”}{print $1,$7} END{print “END_OF_REPORT”}’ data.txt 7. 增加一个域【原来只有11个域】 awk ‘{$12=”AAA”;print $0}’ data 则显示结果中自动多了一个域 8. 修改文本域 awk '{if($1=="M.Tansley") $1="feidd";print $0}' awk.txt 9. 只显示修改的记录 awk ‘{if($1==“M.Tansley”) {$1=“feidd”;print $0}}’ awk.txt (区分和修改文本域的区别) 10.awk ‘{(tot+=$6)};END {print tot}’ awk.txt(只打印tot值) awk ‘(tot+=$6);END {print $0“\n”tot}’ awk.txt(打印所有域) 11.awk ‘{print “hello”,”there”,”Jim”}’ 打印 hello there Jim |
设置域变量&域值比较 |
1. 设置输入域到域变量名 awk ‘{name=$1;belts=$4;if(belts ~/Yellow/) print name}’ data.txt 注:设置了 变量直接输出就是了,不需要使用$进行获取,否则拿不到东西,懂? 2. 域值比较 awk ‘{if($6<27) print $0}’ data.txt 3. 设置对所有记录有效的全局域变量【全局变量放在BEGIN中】 awk ‘BEGIN{LINE=”27”}{if($6<LINE) print $0}’ data.txt |
修改域值【对原文件无影响】 |
1. 修改域值 awk ‘{if($1==”MT”) $6=$6-1;print $1,$6,$7}’ data.txt 【if($1==”MT”) $6=$6-1;符合才执行,其他行都执行print $1,$6,$7】 awk '{if($1=="J.Lulu") $7=$7*2;print $1,$7}' awk.txt 2. 赋新值 awk ‘{if($1==”MT”) $1=”AB”;print $1}’ data.txt 3. 打印每一列并进行了统计 awk ‘(tot+=$6);END{print tot}’ data.txt 4. 只进行统计 awk ‘{(tot+=$6)};END{print tot}’ data.txt
注:修改数值域取值(当在a w k中修改任何域时,重要的一点是要记住实际输入文件是不可修改的,修改的只是保存在缓存里的awk复本) |
正则匹配 |
1. 模糊匹配 awk -F"^A" '{if($0 ~ /id=00001b/) print $0}' test.txt 2. 精确匹配 awk -F"^A" '{if($1 == "<doc>") print $0}' 1 3. 不匹配 awk -F"^A" '{if($0 !~ /id=000015b/) print $0}' test.txt 4. 特殊匹配 匹配大小写 awk '{if($4~/[Gg]reen/) print $0}' awk.txt 匹配任意字符(匹配第四个字符是a的) awk '{if($1~/^...a/) print $0}' awk.txt 关系匹配(注意,使用竖线符时,语句必须用圆括号括起来) awk '{if($4~/(Yellow|green)/) print $0}' awk.txt 5. 不指定域 a.awk ‘/[0-9]/’ data.txt 打印记录中任意列包含数字0-9的行 |
内置变量&操作
awk内置变量 |
|
ARGC |
命令行参数个数 |
ARGV |
命令行参数排列 |
ENVIRON |
支持队列中系统环境变量的使用 |
FILENAME |
实际操作的文件名 |
FS |
设置输入域分隔符,等价于命令行-F选项 Field Separator 可在BEGIN中进行设置,然后执行的时候均以设置的符号为分隔符 |
NF |
浏览记录 域的个数,在记录被读取时设置【number of fields】一共有多少个域 |
NR |
当前记录数(为全部输入文件) 已读取记录数【number of rows】 1 2 3 4 … 全局行数 |
FNR |
当前文件行数,<=NR |
NR与FNR区别 awk ‘{print NR,$0}’ filea fileb 结果:行号是连续的,不区分两个文件 awk ‘{print FNR,$0}’ filea fileb 结果:行号区分两个文件 |
|
RS |
输入记录分隔符(默认为换行符) 缺省:新行\n Row Separator记录分隔符
可以根据具体数据需求,设置读取一条记录的区间 |
OFS |
输出域的分隔符,缺省空格 输出结果 print $1,$2默认加的是空格,可以在BEGIN中设置,改为其他分隔符 |
ORS |
输出记录的分隔符,缺省:新行\n 整体记录的 |
注:可以在BEGIN中配置FS,OFS,RS,ORS已决定输入输出的分隔符【域和行的】 |
|
示例: |
|
1. 打印文件记录数 awk ‘END{print NR}’ data.txt 2. 打印每行记录数,已读记录数,记录内容 awk ‘{print NF,NR,$0} END{print FILENAME}’ data.txt 3. 打印当前所在文件夹 echo $PWD | awk –F / ‘{print $NF}’ 4. 列转化成行 每四列转换成一行 awk '{if (NR%4==0){print $0} else {printf"%s ",$0}}' auction.xml 5. 行转换成列 awk 'BEGIN {RS="^A"} {print $0}' 1 6. 指定FS和OFS,多个分隔符 |
内置函数
内置字符串函数 |
|
gsub(r,s) |
在整个$0中用s代替r |
gsub(r,s,t) |
在整个t中用s替代r |
index(s,t) |
返回s中字符串t的第一位置 |
length(s) |
返回s长度 |
match(s,r) |
测试s是否包含匹配r的字符串 |
split(s,a,fs) |
在fs上将s分成序列a.fs为分隔符 |
sprint(fmt,exp) |
返回经fmt格式化后的exp |
sub(r,s) |
用$0中最左边最长的子串代替s |
substr(s,p) |
返回字符串s中从p开始的后缀部分 |
substr(s,p,n) |
返回字符串s中从p开始长度为n的后缀部分 |
注意:字符串一定要用双引号括起来,否则当做变量解释,找不到即为空,变成了用空值作了原字符串 |
|
示例: |
|
1. 替换一个字符为另一个 awk ‘gsub(/4842/,4899){print $0}’ data.txt
替换字符串必须加双引号,否则当做变量处理,取到值为空,导致空值替换掉现有的东西
$awk –F : ‘gsub(/Mike/,”KEN”){print $0}’ data 只打印出存在替换操作的行 $awk –F : ‘{ gsub(/Mike/,”KEN”);print $0}’ data 打印出所有行,无论是否替换 2. 字符串中出现的第一位置 awk ‘{print index($0,”e”)}’ data.txt 3. 长度 awk ‘{print length($0)}’ data.txt 4. 匹配 awk ‘BEGIN{print match(“ANCD”,/D/)}’ 返回结果4,即开始下标 若不匹配,返回0 5. 切分 awk ‘BEGIN{split(“1#2#3”,myarray,”#”);print length(myarray)}’
$awk ‘BEGIN{STR=”1#2#3”;split(STR,myarray,”#”)}{for(x in myarray){print myarray[x]}}’ 6. 发现并替换【注:sub函数的第三个参数不可直接用字符串,而必须用字符串变量】 awk ‘sub(/26/,”29”,$0)’ data.txt 将字符串变量指定字符中第一个符合含有o的用0替换调 awk ‘END{str=”How are you doing?”;sub(/o/,”0”,str);print str}’ data.txt 7. 截取字符串 awk ‘BEGIN{print substr(“abcdefg”,1,3)}’ 8. 数学函数 awk ‘{print 2^5+sin(2.1)+int(0.9)}’ data.txt 在每一行都打印运算值(32.8632) 9. 大小写转换 awk ‘{print toupper($2), tolower($2)}’ data.txt awk ‘END{print match(“How are you you?”,/you/),RSTART,RLENGTH}’ data.txt |
【注意要自己换行,\n】
awk使用printf进行格式化输出 |
|
%c |
ASCII字符 |
%d |
整数 |
%e |
浮点数,可科学计数法 |
%f |
浮点数,小数形式 |
%g |
由awk决定使用哪种浮点数转换e或f |
%o |
八进制 |
%s |
字符串 |
%x |
十六进制 |
示例 |
|
1. 字符串转换 echo “65”| awk ‘{printf “%c\n”,$0 }’ 将输出A 2. 格式化输出 awk ‘{printf ‘%-15s %s \n’,$1,$3}’ data.txt 左对齐十五个字符等长 参数及脚本 |
数组 |
1. awk中数组的使用 awk ‘BEGIN{split(“1#2#3”,myarray,”#”);for(I in myarray){print myarray[i]}}’
2. 数组 BEGIN{ myarray[0] = “jim” myarray[2] = 456 } for(x in myarray) { print myarray[x] } awk -v b=$line 'BEGIN {split(b,array,"^B")} END {for(i in array) {print array[i]}}'
3. Awk数组(打印数组) #!/bin/sh cat aa.txt | while read line do #传入参数line的值 echo "aaa" | awk -v b=$line 'BEGIN {split(b,array,"^B")} END {for(i in array) {print array[i]}}' Done awk 'BEGIN {RS="^B"} {print $0}' aa.txt |
数组 |
F. 流程控制: 1 if(){….}else{if()….} 2 while语句 3 do-while语句 4 for(;;){….} 5 exit; (不在END中,文件尾;END中,程序结束) break(中断当前正在执行的循环并跳到循环外执行下一条语句); continue(从当前位置跳到循环开始处执行 )
|
条件测试 |
< <= > >= == != ~匹配正则 !~不匹配正则 &&(与)、||(或)和括号() |
1. 小于 awk '{if($6<$7) print $0}' awk.txt 2. 小于等于 awk '{if($6<=$7) print $0}' awk.txt 3. 大于 awk '{if($6>$7) print $0}' awk.txt 4. 打印最后一个域为44的 awk ‘$7==”44” {print $0}’ data.txt 5. 打印第四个字段为G开头的 awk ‘{if($4 ~/G*/) print $0} data.txt 6. 打印第四字段非Brown的 awk ‘{if($4 !~/Brown/) print $0}’ data.txt 7. 比较最后两个字段符合的 awk ‘{if($6 < $7) print $0 “ABC”}’ data.txt 8. 多条件 && || ! awk ‘{if($1 == “A” && $2==”B”) print $0}’ data.txt |
for循环 |
for(x = 1 ; x<=4 ; x++) { Print “interation”,x }
|
while循环 |
x=1 while(x<NF){ print $x “\t” x++ if(x == 2) { break } } count=1 |
do while |
do{ print “” }while(count != 1) |
数组 |
交互 |
1. 将shell命令的执行结果送给awk处理 : s=`du -k ./diff" | awk '{ print $1 }'`
2. shell script程序读awk的执行结果 :`` 在awk中执行shell命令行 :嵌入函数system() END{print count;system("ls ./");} |
传参 |
向一行awk传递参数 awk ‘{if($5<AGE) print $0}’ AGE=10 data.txt awk –v AGE=10 ‘{if($5<AGE) print $0}’ data.txt |
数组 |
Awk 变量内置变量 1 直接引用,不加$($NF) 自定义变量 1 用户自定义(不要与内置变量冲突) 2 直接引用,不加$ 3 不需要对变量进行初始化 (默认其为字符串类型 ) |
1. 自定义 awk '{line="44"} {if($7>=line) print $1 " is best"}' awk.txt awk ‘{if($7>=“44”) print $1 “ is best”}’ awk.txt两者相同 2. 运用对比 A. $awk –F : ‘BEGIN{NAME=”123131”}{print NAME}’ data 打印 123131 B. $awk –F : ‘BEGIN{NAME=”123131”}{print $NAME}’ data 什么都不打印 C. $awk –F : ‘BEGIN{NAME=”123131”}{print ‘$NAME’}’ data 打印出所有行,应该是$NAME 变成 $0了 D. $awk –F : ‘BEGIN{NAME=”123131”}{print “$NAME”}’ data 打印出$NAME |
错误排查 |
在碰到awk错误时,可从下面几个方面查找: 确保整个awk命令用单引号括起来。 确保命令内所有引号成对出现。 确保用花括号括起动作语句,用圆括号括起条件语句。
切记有两条规则可以帮助您避免出现语法错误: 1. 确保命令位于括号中,而括号位于单引号中。没有使用这些字符之一必然导致程序无法运行。 2. 搜索命令需要位于斜线之间。要找出住在印第安那州的员工,您必须使用“/IN/”而不是“IN”。
其他注意: A.从window拷贝语法句到Unix中,行结尾可能有不识别的字符会导致语法错误 |
其他 |
调用脚本 |
stu.awk !/bin/awk –f BEGIN{ print”ABC” print “DEF” } {total+=56} END{ print “Total” total print “AVG” total/WR } |
自定义函数 |
定义方法如下: function 函数名(参数表){ 函数体 } 直接调用,但不执行参数有效性检查 (多余的参数会被awk所忽略,而不足的参数,awk将它们置为缺省值0或空字符串 ) 返回值:return 返回值 |
重定向输出和特别函数getline实例 |
a.awk ‘{print FILENAME,$0}’ data1.txt data2.txt >data_all.txt |
一个例子 |
从一个有6千多万行的文件中,每6千行提取一行; 第一种方法: 第2种方法: awk '(NR%6000==0){print $0}' $inputFile |