AWK编程总结(1)

AWK综述

awk 适合于文本处理和报表生成。

1 .AWK调用

调用awk有三种方法(与sed类似):

1)在Shell命令行输入命令调用awkawk [-F 域分隔符] awk程序段’输入文件

2)将awk程序段插入脚本文件后,然后通过awk命令调用它:awk -f awk脚本文件输入文件【脚本文件的首行不以#!/bin/awk f开头】

3)将awk命令插入脚本文件后,设置该脚本文件为可执行,然后直接执行该脚本文件,格式为:

   ./awk脚本文件输入文件  【脚本文件的首行以#!/bin/awk f开头】

 

1.1 以下以调用方式1为例展示AWK命令用法:

如执行$ awk '{ print }' /etc/passwd,会见到 /etc/passwd 文件的内容出现在眼前。调用 awk 时,指定 /etc/passwd 作为输入文件。执行 awk 时,它依次对 /etc/passwd 中的每一行执行 print 命令。所有输出都发送到 stdout,所得到的结果与与执行catting /etc/passwd完全相同。

另一个相同作用的 awk 示例:$ awk '{ print $0 }' /etc/passwd

awk 中,$0 变量表示整个当前行,所以 print print $0 的作用完全一样。

还可以创建一个 awk 程序,让它输出与输入数据完全无关的数据。以下是一个示例:$ awk '{ print "" }' /etc/passwd

只要将 "" 字符串传递给 print 命令,它就会打印空白行。如果测试该脚本,将会发现对于 /etc/passwd 文件中的每一行,awk 都输出一个空白行。再次说明, awk 对输入文件中的每一行都执行这个脚本。

 

awk 非常善于处理分成多个逻辑字段的文本,可以毫不费力地引用 awk 脚本中每个独立的字段。以下脚本将打印出系统上所有用户帐户的列表:

$ awk -F":" '{ print $1 }' /etc/passwd

上例中,在调用 awk 时,使用 -F 选项来指定 ":" 作为字段分隔符。awk 处理 print $1 命令时,它会打印出在输入文件中每一行中出现的第一个字段。

  

   同理,外部文件的输入大抵如此。

将脚本作为命令行自变量传递给 awk 对于小的单行程序来说是非常简单的,而对于多行程序,它就比较复杂。在外部文件中撰写脚本。然后可以向 awk 传递 -f 选项,以向它提供此脚本文件:

$ awk -f myscript.awk myfile.in

将脚本放入文本文件还可以使用附加 awk 功能。例如,这个多行脚本与前面的单行脚本的作用相同,它们都打印出 /etc/passwd 中每一行的第一个字段:

BEGIN {

FS=":"

}

{ print $1 }

这两个方法的差别在于如何设置字段分隔符。在这个脚本中,字段分隔符在代码自身中指定(通过设置 FS 变量),而在前一个示例中,通过在命令行上向 awk 传递 -F":" 选项来设置 FS。通常,最好在脚本自身中设置字段分隔符,只是因为这表示您可以少输入一个命令行自变量。

 

1.2 BEGIN END

上例中提及了BEGINEND块。下面来简述一下该部分内容。

通常,对于每个输入行,awk 都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk 允许定义一个 BEGIN 块。

BEGIN块对应,awk 还提供了另一个特殊块,叫作 END 块。awk 在处理了输入文件中的所有行之后执行这个块。通常,END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

 

 

1.3 规则表达式和块

awk 允许使用规则表达式,根据规则表达式是否匹配当前行来选择执行独立代码块。以下示例脚本只输出包含字符序列 foo 的那些行:/foo/ { print }

以下脚本将只打印包含浮点数的行:/[0-9]+\.[0-9]*/ { print }

 

1.4 AWK内部变量解析

awk认为输入文件是结构化的,awk将每个输入文件行定义为记录,行中的每个字符串定义为域,域之间用空格、Tab键或其他符号进行分割,分割域的符号就叫分隔符。

 

awk提供的内建变量(变量名全部大写)如下:

 

ARGC命令行参数的数量。

ARGIND :命令行正在处理的当前文件的AGV的索引。

ARGV :命令行参数数组。

CONVFMT :转换数字格式。

ENVIRON :从shell中传递来的包含当前环境变量的数组。

ERRNO :当使用close函数或者通过getline函数读取的时候,发生的重新定向错误的描述信息就保存在这个变量中。

FIELDWIDTHS :在对记录进行固定域宽的分割时,可以替代FS的分隔符的列表。

FILENAME :当前的输入文件名。

FNR :当前文件的记录号。

FS :输入分隔符,默认是空格。

IGNORECASE在正则表达式和字符串操作中关闭大小写敏感。

NF :当前文件域的数量。

NR :当前文件记录数。

OFMT :数字输出格式。

OFS输出域分隔符。

ORS输出记录分隔符。

RLENGTH :通过match函数匹配的字符串的长度。

RS :输入记录分隔符。

RSTART :通过match函数匹配的字符串的偏移量。

SUBSEP :下标分隔符。

 

 

先来看几个简单的小例子:

BEGIN {

FS="\n"

RS=""

}

在上面这段代码中,将 FS 设置成 "\n" 告诉 awk 每个字段都占据一行。通过将 RS 设置成 "",还会告诉 awk 每个地址记录都由空白行分隔。

 

BEGIN {

FS="\n"

RS=""

OFS=", "

}

{

print $1, $2, $3

}

缺省情况下的输出结果,OFS 被设置成 " ",单个空格。不过,我们可以方便地重新定义 OFS,这样 awk 将插入我们中意的字段分隔符。它使用 OFS 来输出那些中间的 ", " 字符串

 

awk 还有一个特殊变量 ORS,全称是“输出记录分隔符”。通过设置缺省为换行 ("\n") OFS,我们可以控制在 print 语句结尾自动打印的字符。缺省 ORS 值会使 awk 在新行中输出每个新的 print 语句。如果想使输出的间隔翻倍,可以将 ORS 设置成 "\n\n"。或者,如果想要用单个空格分隔记录(而不换行),将 ORS 设置成 ""

 

1.5 AWK重定向

AWK的重定向与Linux/Unix重定向基本一致。

    在动作语句中使用shell通用的重定向输出符号">"就可以完成awk的重定向操作,当使用>的时候,原有文件将被清空,同时文件持续打开,直到文件被明确的关闭或者awk程序终止。来自后面的打印语句的输出会追加到前面内容的后面。符号">>"用来打开一个文件但是不清空原有文件的内容,重定向的输出只是被追加到这个文件的末尾。

    /> awk '$4 >= 70 {print $1,$2 > "passing_file"}' filename  #注意文件名需要用双引号括起来。

   

    awk中对于输入重定向是通过getline函数来完成的。getline函数的作用是从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。他负责从输入获得下一行的内容,并给NFNRFNR等内建变量赋值。如果得到一个记录,getline就返回1,如果达到文件末尾就返回0。如果出现错误,如打开文件失败,就返回-1

    /> awk 'BEGIN { "date" | getline d; print d}'

    Tue Nov 15 15:31:42 CST 2011

    上例中的BEGIN动作模块中,先执行shell命令date,并通过管道输出给getline,然后再把输出赋值给自定义变量d并打印输出它。

   

    /> awk 'BEGIN { "date" | getline d; split(d,mon); print mon[2]}'

    Nov

    上例中date命令通过管道输出给getline并赋值给d变量,再通过内置函数splitd拆分为mon数组,最后printmon数组的第二个元素。

   

    /> awk 'BEGIN { while("ls" | getline) print}'

    employees

    employees2

    testfile

    命令ls的输出传递给getline作为输入,循环的每个反复,getline都从ls的结果中读取一行输入,并把他打印到屏幕。

   

    /> awk 'BEGIN { printf "What is your name? "; \

        getline name < "/dev/tty"}\

        $1 ~ name {print "Found" name " on line ", NR "."}\

        END {print "See ya, " name "."}' employees2

    What is your name? Mary

    Found Mary on line  2.

    See ya, Mary.   

    上例先是打印出BEGIN块中的"What is your name? ",然后等待用户从/dev/tty输入,并将读入的数据赋值给name变量,之后再从输入文件中读取记录,并找到匹配输入变量的记录并打印出来,最后在END块中输出结尾信息。

   

    /> awk 'BEGIN { while(getline < "/etc/passwd" > 0) lc++; print lc}'

    32

    awk将逐行读取/etc/passwd文件中的内容,在达到文件末尾之前,计数器lc一直自增1,当到了末尾后打印lc的值。lc的值为/etc/passwd文件的行数。

    由于awk中同时打开的管道只有一个,那么在打开下一个管道之前必须关闭它,管道符号右边可以通过可以通过双引号关闭管道。如果不关闭,它将始终保持打开状态,直到awk退出。

    /> awk {print $1,$2,$3 | "sort -4 +1 -2 +0 -1"} END {close("sort -4 +1 -2 +0 -1") } filename

    上例中END模块中的close显示关闭了sort的管道,需要注意的是close中关闭的命令必须和当初打开时的完全匹配,否则END模块产生的输出会和以前的输出一起被sort分类。

猜你喜欢

转载自aoyouzi.iteye.com/blog/1863473