AWK命令简记

来源:互联网 发布:java 任波 编辑:程序博客网 时间:2024/05/18 00:02

一、简介

  AWK是一种优良的文本处理工具。它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一。AWK 在很多方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的语法。它的设计思想来源于 SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工具 yacc 和 lex ,当然还从 C 语言中获取了一些优秀的思想。在最初创造 AWK 时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。


二、语法

awk [option] ' BEGIN { actions } awk_pattern1 { actions } ... awk_patternN { actions } END { actions } ' inputfiles

1. 常用的option选项有:

    ① -F fs : 使用fs作为输入记录的字段分隔符,如果省略该选项,awk使用环境变量IFS的值。 注意,fs取值为字符串或正则表达式,而因为在引号中,需要加反斜杠的需要加双反斜杠,故以'$$$'为分隔符的写法为‘\\$\\$\\$’。
    ② -f filename : 从文件filename中读取awk_script(即awk_patternX { actions })。
    ③ -v var=value : 为awk_script设置变量。

2. 执行过程:

    ① awk执行BEGIN指定的actions。 
    ② awk从输入文件中读取一行,称为一条输入记录。(如果输入文件省略,将从标准输入读取)。
    ③ awk将读入的记录分割成字段,将第1个字段放入变量$1中,第2个字段放入$2,以此类推。$0表示整条记录。字段分隔符使用shell环境变量IFS或由参数指定。 
    ④ 把当前输入记录依次与每一个awk_cmd中awk_pattern比较,看是否匹配,如果相匹配,就执行对应的actions。如果不匹配,就跳过对应的actions,直到比较完所有的awk_cmd。 
    ⑤ 当一条输入记录比较了所有的awk_cmd后,awk读取输入的下一行,继续重复步骤③和④,这个过程一直持续,直到awk读取到文件尾。 
    ⑥ 当awk读完所有的输入行后,就执行END相应的actions。

3. 说明:

    ① iput_file可以是多于一个文件的文件列表,awk将按顺序处理列表中的每个文件。
    ② 一条awk_cmd的awk_pattern可以省略,省略时不对输入记录进行匹配比较就执行相应的actions。一条awk_cmd的actions 也可以省略,省略时默认的动作为打印当前输入记录(print $0) 。
    ③ BEGIN区块和END区块别位于awk_script的开头和结尾。awk_script中只有END区块或者只有BEGIN区块是被允许的。如果awk_script中只有BEGIN { actions } ,awk不会读取input_file。 
    ④ awk把输入文件的数据读入内存,然后操作内存中的输入数据副本,awk不会修改输入文件的内容。awk的总是输出到标准输出,如果想让awk输出到文件,可以使用重定向。

4. 范例:

1. 基本示例

awk '{print $0}' test.txt   #打印文件的全部内容awk '{print $1}' test.txt   #抽取文件test.txt中的第一列awk -F : '{print $1,$6}' /etc/passwd   #列出所有的用户名和登陆的shell名awk -F : '$1=="root" {print $0}' /etc/passwd    #只打印用户名为root的那一行awk -F ":" '( $1 == "foo" ) && ( $2 == "bar" ) { print }' /etc/passwd #打印第1列为foo,第2列为bar的行

2. 给输出信息加上表头

awk -F : 'BEGIN {print "name        shell\n--------------------------------"}    {print $1"\t"$6}     END {print "---------------------------\nend-of-report"}' \    /etc/passwdawk -F: '$1 ~ /^root/' /etc/passwd  #打印第一个列以root开头的行awk -F: '$1 !~ /root/' /etc/passwd  #打印第一个列不含有root的行tail -n $N $filename | awk '{if(NR==1) print $0}'   #输出文件的倒数第N行

3. 数据处理示例

#文件中第1列为用户id,第2列为用户区号,第3列为用户服务器号,包含了一天的数据。例如#0001,001,1#0001,001,2#0002,001,1#0001,002,2#0002,002,1#以下命令统计每个区有多少不同的用户awk -F, '{if(!b[$1$2]){a[$2]++;b[$1$2]++}}END{for(i in a){print i,a[i]}}' test.txt

4. if的用法,类似C

awk -F ":" '{    if ( $1 == "root" ) {        if ( $2 == "x" ) {            print "zero"        } else {            print "one"        }    } else if ($1 == "mail" ) {        print "two"    } else {        print "three"    }}' /etc/passwd

5. 统计文件的空白行数

awk 'BEGIN   { x=0 }/^$/    { x=x+1 }END     { print "I found " x " blank lines. :)" }' inputdata.txt

6. 自定义分隔符,把行当作字段处理

#对如下文件address.txt进行操作,每三行为一个地址信息#Jimmy the Weasel#100 Pleasant Drive#San Francisco, CA 12345##Big Tony#200 Incognito Ave.#Suburbia, WA 67890#把以上文件按地址信息分割为每行的记录,地址信息的内容用逗号分割awk '          BEGIN {    FS="\n"    RS=""    OFS=", "}{    print $1, $2, $3}' address.txt#仍是以上例子,只是文件中有4行分割的地址awk 'BEGIN {     FS="\n"     RS=""     ORS="" }  {          x=1         while ( x<NF ) {                 print $x "\t"                 x++         }         print $NF "\n" }' address.txt#数组的使用awk 'BEGIN {myarray[1]="jim"myarray[2]=456for ( x in myarray ) {    print myarray[x]}delete myarray[1]if ( "jim" in myarray ) {    print "Ayep! It'"\'"'s here."} else {    print "Nope! Can'"\'"'t find it."}}'

7. 字符串函数的使用

awk 'BEGIN {mystring="How are you doing today?"print length(mystring) #24print index(mystring,"you") #9print tolower(mystring) #how are you doing today?print toupper(mystring) #HOW ARE YOU DOING TODAY?print substr(mystring,9,3) #youprint match(mystring,/you/), RSTART, RLENGTH #9 9 3print mystring #How are you doing today?sub(/o/,"@",mystring)print mystring #H@w are you doing today?mystring="How are you doing today?"gsub(/o/,"@",mystring)print mystring #H@w are y@u d@ing t@day?num=split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mymonths,",")print mymonths[1],mymonths[num] #Jan Dec}'

8. 字符串匹配并提取

$ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'   #11,11,4awk '{if(match($0, /<[^\/]*>/))print substr($0,RSTART,RLENGTH)}' test.txt  #提取并打印test.txt中的所有<xxxx>的html标签,但不要<\xxx>的结束标签


9. 处理多个文件

处理2个文件时,使用如下方法判断是在处理哪个文件:

awk 'NR==FNR{第1个文件...}NR>FNR{第2个文件...}' file1 file2

awk 'NR==FNR{第1个文件...}NR!=FNR{第2个文件...}' file1 file2

处理多个文件时,使用如下方法来判断是在处理哪个文件:

1. ARGIND # 当前被处理参数标志

awk 'ARGIND==1{...}ARGIND==2{...}ARGIND==3{...}... ' file1 file2 file3 ...
2. ARGV # 命令行参数数组

awk 'FILENAME==ARGV[1]{...}FILENAME==ARGV[2]{...}FILENAME==ARGV[3]{...}...' file1 file2 file3 ...

举例:

#现有file1,file2 两个文件。文件file1有2列,内容如:#no1 name1#no2 name2#文件file2 有6列,部分有空格,内容如下:#name1 data1 dada2 data3 data4 dada5#name2 dada6 data7 dada8#如果file1的第2列跟file2的第1列匹配,则将两条数据合并成一条,合并后的数据应该是这样的:#no1 name1 data1 dada2 data3 data4 dada5#no2 name2 dada6 data7 dada8awk 'NR==FNR{a[$1]=$0}NR>FNR{print $1" "a[$2]}' file2 file1



5. 实战笔记(用法详细总结):

1) BEGIN、END不可以小写。
2) {actions}中,每一行为一个语句,同一行可以使用分号;来分割语句,这个类似于shell格式。
3) 字符串连接直接列在一起,类似于shell格式。
4) print函数可以接受逗号分隔的多个参数,并以字段分隔符OFS分隔来打印。通过设置记录分隔符OFS,我们可以控制在 print 语句结尾自动打印的字符。也支持printf函数,和c语言格式一致。-F参数的形式可以使用以下任一方式:-F: 或 -F ":"。
5)awk 提供了完整的比较运算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 还提供了 "~" 和 "!~" 运算符,它们分别表示“匹配”和“不匹配”。它们的用法是在运算符左边指定变量,在右边指定规则表达式。
6) awk 还允许使用布尔运算符 "||"(逻辑与)和 "&&"(逻辑或),以便创建更复杂的布尔表达式
7) 只要变量包含有效数字字符串,awk 会自动处理字符串到数字的转换步骤。例如:x="2.01";x=x+1;#x=3.01。如果某个特定变量不包含有效数字,awk 在对数学表达式求值时会将该变量当作数字零处理。
8) awk有完整的数学运算符集合,包括加、减、乘、除,指数运算符 "^"、模(余数)运算符 "%" ;运算符包括前后加减( i++ 、 --foo )、加/减/乘/除/指数/余数赋值运算符( a+=3 、 b*=2 、 c/=2.2 、 d-=6.2 、 e^=2 、 f%=7)。
9) awk支持和C语言一致的条件控制和循环控制,如if(条件){}else if(条件){}else(条件){}、while(条件){}、do{}while(条件)、for(初始值化;比较;递增){}、continue、break。也支持exit 0/1(非0表示异常)退出遍历和处理每一行的过程,但是会执行END块。
10) awk可以使用数组,变量直接使用下标赋值即可创建数组,数组的下标从1开始;for ( x in myarray )打印的数字并不是按下标顺序,而是随机的。
11) awk调用shell的方法:1. 使用system函数,该函数的返回值为状态码$?,例如{cmdstr="cp $1 $2";st=system(cmdstr);if(st==0){print "copy success!";}else{print "copy failed!"} 2. 使用{cmdstr="cp $1 $2"; cmdstr|getline [var]}可以获取执行shell结果的返回值,如果带var参数则返回值放在var变量中,否则覆盖至$0变量中。
12) awk使用变量的注意事项:1. 当使用awk ‘xxx’ 时,xxx的内容里,如果引用变量,不能位于双引号内,而应该使用类似“something”$0"otherthing"的形式。 2. 使用shell变量时,可以使用-v var=value选项的方式。例如awk  test="$test" '{print test}' ./inputfile.txt
13) 因为awk没有内部变量标识总行数(总记录数),故可以使用外部变量的方式获取,即 -v linenum=`wc -l ./inputfile | cut -d ' ' -f 1`


三、内置变量

  FILENAME   #当前正在处理的文件名,该变量不能在BEGIN块中使用。  FNR   #当前处理的记录号,但是FNR的作用域只在一个文件内.如果重新打开文件,FNR会从1开始  FS   #字段的分隔符,默认为空格。  IGNORECASE   #如果该变量设置为非0值,在进行字符串匹配时忽略大小写。  NF   #当前记录中的字段个数  NR   #已经读出的记录数  OFMT   #数字的输出格式  OFS   #输出的字段分隔符,默认为空格  ORS   #输出的记录分隔符,默认为新行  RS   #输入记录的分隔符,默认为新行  RSTART   #被match()函数匹配的字符串的起始位置,如果没有匹配则为0(从1开始)  RLENGTH   #被match()函数匹配的字符串的长度  SUBSEP   #数组中多个下标的分隔符,默认为"\034"

四、内置的字符串函数

gsub(r,s)   #在整个$0中用s代替rgsub(r,s,t)   #在整个t中用s替代rindex(s,t)   #返回s中字符串t的第一位置length(s)   #返回s长度match(s,r)   #测试s是否包含匹配r的字符串split(s,a,fs)   #在fs上将s分成序列asprint(fmt,exp)   #返回经fmt格式化后的expsub(r,s)   #用$0中最左边最长的子串代替ssubstr(s,p)   #返回字符串s中从p开始的后缀部分substr(s,p,n)   #返回字符串s中从p开始长度为n的后缀部分


原创粉丝点击