AWK

一、简介

  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/passwd
awk -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]=456
for ( 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) #24
print index(mystring,"you") #9
print tolower(mystring) #how are you doing today?
print toupper(mystring) #HOW ARE YOU DOING TODAY?
print substr(mystring,9,3) #you
print match(mystring,/you/), RSTART, RLENGTH #9 9 3
print 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
}
'

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";system(cmdstr) 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代替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
sprint(fmt,exp) 返回经fmt格式化后的exp
sub(r,s) 用$0中最左边最长的子串代替s
substr(s,p) 返回字符串s中从p开始的后缀部分
substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值