• linux之awk手册


    awk 手册

     

    原文

    Table of Contents

    1. awk简介
    2. awk命令格式和选项
    2.1. awk的语法有两种形式
    2.2. 命令选项
    3. 模式和操作
    3.1. 模式
    3.2. 操作
    4. awk的环境变量
    5. awk运算符
    6. 记录和域
    6.1. 记录
    6.2. 域
    6.3. 域分隔符
    7. gawk专用正则表达式元字符
    8. POSIX字符集
    9. 匹配操作符(~)
    10. 比较表达式
    11. 范围模板
    12. 一个验证passwd文件有效性的例子
    13. 几个实例
    14. awk编程
    14.1. 变量
    14.2. BEGIN模块
    14.3. END模块
    14.4. 重定向和管道
    14.5. 条件语句
    14.6. 循环
    14.7. 数组
    14.8. awk的内建函数
    15. How-to
     

    1. awk简介


    awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和 动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk的处理文本和数据的方式是这 样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出 (屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在 linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。

    2. awk命令格式和选项


    2.1. awk的语法有两种形式

    • awk [options] ’script’ var=value file(s)
    • awk [options] -f scriptfile var=value file(s)

    2.2. 命令选项

     

    • -F fs or –field-separator fs
    • 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
    • -v var=value or –asign var=value
    • 赋值一个用户定义变量。
    • -f scripfile or –file scriptfile
    • 从脚本文件中读取awk命令。
    • -mf nnn and -mr nnn
    • 对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
    • -W compact or –compat, -W traditional or –traditional
    • 在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
    • -W copyleft or –copyleft, -W copyright or –copyright
    • 打印简短的版权信息。
    • -W help or –help, -W usage or –usage
    • 打印全部awk选项和每个选项的简短说明。
    • -W lint or –lint
    • 打印不能向传统unix平台移植的结构的警告。
    • -W lint-old or –lint-old
    • 打印关于不能向传统unix平台移植的结构的警告。
    • -W posix
    • 打开兼容模式。但有以下限制,不识别:x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。
    • -W re-interval or –re-inerval
    • 允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
    • -W source program-text or –source program-text
    • 使用program-text作为源代码,可与-f命令混用。
    • -W version or –version
    • 打印bug报告信息的版本。


     

    3. 模式和操作


    awk脚本是由模式和操作组成的:

    pattern {action} 如$ awk ‘/root/’ test,或$ awk ‘$3 < 100′ test。

    两者是可选的,如果没有模式,则action应用到全部记录,如果没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。


     

    3.1. 模式

    模式可以是以下任意一个:

    • /正则表达式/:使用通配符的扩展集。
    • 关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
    • 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
    • 模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
    • BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
    • END:让用户在最后一条输入记录被读取之后发生的动作。 

    3.2. 操作

    操作由一人或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内。主要有四部份:

    • 变量或数组赋值
    • 输出命令
    • 内置函数
    • 控制流命令

    4. awk的环境变量


     

    Table 1. awk的环境变量

    变量描述
    $n 当前记录的第n个字段,字段间由FS分隔。
    $0 完整的输入记录。
    ARGC 命令行参数的数目。
    ARGIND 命令行中当前文件的位置(从0开始算)。
    ARGV 包含命令行参数的数组。
    CONVFMT 数字转换格式(默认值为%.6g)
    ENVIRON 环境变量关联数组。
    ERRNO 最后一个系统错误的描述。
    FIELDWIDTHS 字段宽度列表(用空格键分隔)。
    FILENAME 当前文件名。
    FNR 同NR,但相对于当前文件。
    FS 字段分隔符(默认是任何空格)。
    IGNORECASE 如果为真,则进行忽略大小写的匹配。
    NF 当前记录中的字段数。
    NR 当前记录数。
    OFMT 数字的输出格式(默认值是%.6g)。
    OFS 输出字段分隔符(默认值是一个空格)。
    ORS 输出记录分隔符(默认值是一个换行符)。
    RLENGTH 由match函数所匹配的字符串的长度。
    RS 记录分隔符(默认是一个换行符)。
    RSTART 由match函数所匹配的字符串的第一个位置。
    SUBSEP 数组下标分隔符(默认值是34)。

    5. awk运算符


     

    Table 2. 运算符

    运算符描述
    = += -= *= /= %= ^= **= 赋值
    ?: C条件表达式
    || 逻辑或
    && 逻辑与
    ~ ~! 匹配正则表达式和不匹配正则表达式
    < <= > >= != == 关系运算符
    空格 连接
    + - 加,减
    * / & 乘,除与求余
    + – ! 一元加,减和逻辑非
    ^ *** 求幂
    ++ – 增加或减少,作为前缀或后缀
    $ 字段引用
    in 数组成员

    6. 记录和域


    6.1. 记录

    awk把每一个以换行符结束的行称为一个记录。

    记录分隔符:默认的输入和输出的分隔符都是回车,保存在内建变量ORS和RS中。

    $0变量:它指的是整条记录。如$ awk ‘{print $0}’ test将输出test文件中的所有记录。

    变量NR:一个计数器,每处理完一条记录,NR的值就增加1。如$ awk ‘{print NR,$0}’ test将输出test文件中所有记录,并在记录前显示记录号。

    6.2. 域

    记录中每个单词称做“域”,默认情况下以空格或tab分隔。awk可跟踪域的个数,并在内建变量NF中保存该值。如$ awk ‘{print $1,$3}’ test将打印test文件中第一和

    第三个以空格分开的列(域)。

    6.3. 域分隔符

    内建变量FS保存输入域分隔符的值,默认是空格或tab。我们可以通过-F命令行选项修改FS的值。如$ awk -F: ‘{print $1,$5}’ test将打印以冒号为分隔符的第一,第五列的内容。

    可以同时使用多个域分隔符,这时应该把分隔符写成放到方括号中,如$awk -F’[: ]‘ ‘{print $1,$3}’ test,表示以空格、冒号和tab作为分隔符。

    输出域的分隔符默认是一个空格,保存在OFS中。如$ awk -F: ‘{print $1,$5}’ test,$1和$5间的逗号就是OFS的值。

    7. gawk专用正则表达式元字符


    一般通用的元字符集就不讲了,可参考我的SedGrep学习笔记。以下几个是gawk专用的,不适合unix版本的awk。

    • Y       匹配一个单词开头或者末尾的空字符串。
    • B     匹配单词内的空字符串。
    • <    匹配一个单词的开头的空字符串,锚定开始。
    • >    匹配一个单词的末尾的空字符串,锚定末尾。
    • w   匹配一个字母数字组成的单词。
    • W   匹配一个非字母数字组成的单词。
    • ‘    匹配字符串开头的一个空字符串。
    • ’    匹配字符串末尾的一个空字符串。

    8. POSIX字符集


    可参考我的Grep学习笔记

    9. 匹配操作符(~)


    用来在记录或者域内匹配正则表达式。如$ awk ‘$1 ~/^root/’ test将显示test文件第一列中以root开头的行。

    10. 比较表达式


    conditional expression1 ? expression2: expression3,例如:$ awk ‘{max = {$1 > $3} ? $1: $3: print max}’ test。如果第一个域大于第三个域,$1就赋值给max,否则$3就赋值给max。

    $ awk ‘$1 + $2 < 100′ test。如果第一和第二个域相加大于100,则打印这些行。

    $ awk ‘$1 > 5 && $2 < 10′ test,如果第一个域大于5,并且第二个域小于10,则打印这些行。

    11. 范围模板


    范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现之间所有行。如果有一个模板没出现,则匹配到开头或末尾。如$ awk ‘/root/,/mysql/’ test将显示root第一次出现到mysql第一次出现之间的所有行。

    12. 一个验证passwd文件有效性的例子


    $ cat /etc/passwd | awk -F: '
    NF != 7{
    printf("line %d,does not have 7 fields:%sn",NR,$0)}
    $1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %sn,NR,$0)}
    $2 == "*" {printf("line %d, no password: %sn",NR,$0)}'
    
      cat把结果输出给awk,awk把域之间的分隔符设为冒号。
      如果域的数量(NF)不等于7,就执行下面的程序。
      printf打印字符串”line ?? does not have 7 fields”,并显示该条记录。
      如果第一个域没有包含任何字母和数字,printf打印“no alpha and numeric user id” ,并显示记录数和记录。
      如果第二个域是一个星号,就打印字符串“no passwd”,紧跟着显示记录数和记录本身。

    13. 几个实例


    • $ awk ‘/^(no|so)/’ test—–打印所有以模式no或so开头的行。
    • $ awk ‘/^[ns]/{print $1}’ test—–如果记录以n或s开头,就打印这个记录。
    • $ awk ‘$1 ~/[0-9][0-9]$/(print $1}’ test—–如果第一个域以两个数字结束就打印这个记录。
    • $ awk ‘$1 == 100 || $2 < 50′ test—–如果第一个或等于100或者第二个域小于50,则打印该行。
    • $ awk ‘$1 != 10′ test—–如果第一个域不等于10就打印该行。
    • $ awk ‘/test/{print $1 + 10}’ test—–如果记录包含正则表达式test,则第一个域加10并打印出来。
    • $ awk ‘{print ($1 > 5 ? “ok “$1: “error”$1)}’ test—–如果第一个域大于5则打印问号后面的表达式值,否则打印冒号后面的表达式值。
    • $ awk ‘/^root/,/^mysql/’ test—-打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记 录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾。

    14. awk编程


    14.1. 变量

    • 在awk中,变量不需要定义就可以直接使用,变量类型可以是数字或字符串。
    • 赋 值格式:Variable = expression,如$ awk ‘$1 ~/test/{count = $2 + $3; print count}’ test,上式的作用是,awk先扫描第一个域,一旦test匹配,就把第二个域的值加上第三个域的值,并把结果赋值给变量count,最后打印出来。
    • awk 可以在命令行中给变量赋值,然后将这个变量传输给awk脚本。如$ awk -F: -f awkscript month=4 year=2004 test,上式的month和year都是自定义变量,分别被赋值为4和2004。在awk脚本中,这些变量使用起来就象是在脚本中建立的一样。注意,如 果参数前面出现test,那么在BEGIN语句中的变量就不能被使用。
    • 域变量也可被赋值和修改,如$ awk ‘{$2 = 100 + $1; print }’ test,上式表示,如果第二个域不存在,awk将计算表达式100加$1的值,并将其赋值给$2,如果第二个域存在,则用表达式的值覆盖$2原来的值。 再例如:$ awk ‘$1 == “root”{$1 =”test”;print}’ test,如果第一个域的值是“root”,则把它赋值为“test”,注意,字符串一定要用双引号。
    • 内建变量的使用。 变量列表在前面已列出,现在举个例子说明一下。$ awk -F: ‘{IGNORECASE=1; $1 == “MARY”{print NR,$1,$2,$NF}’test,把IGNORECASE设为1代表忽略大小写,打印第一个域是mary的记录数、第一个域、第二个域和最后一个 域。

    14.2. BEGIN模块

    BEGIN 模块后紧跟着动作块,这个动作块在awk处理任何输入文件之前执行。所以它可以在没有任何输入的情况下进行测试。它通常用来改变内建变量的值,如OFS, RS和FS等,以及打印标题。如:$ awk ‘BEGIN{FS=”:”; OFS=” ”; ORS=” ”}{print $1,$2,$3} test。上式表示,在处理输入文件以前,域分隔符(FS)被设为冒号,输出文件分隔符(OFS)被设置为制表符,输出记录分隔符(ORS)被设置为两个 换行符。$ awk ‘BEGIN{print “TITLE TEST”}只打印标题。

    14.3. END模块

    END不匹配任何的输入文件,但是执行动作块中的所有动作,它在整个输入文件处理完成后被执行。如$ awk ‘END{print “The number of records is” NR}’ test,上式将打印所有被处理的记录数。

    14.4. 重定向和管道

    • awk 可使用shell的重定向符进行重定向输出,如:$ awk ‘$1 = 100 {print $1 > “output_file” }’ test。上式表示如果第一个域的值等于100,则把它输出到output_file中。也可以用>>来重定向输出,但不清空文件,只做追加 操作。
    • 输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件 获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返 回0,如果出现错误,例如打开文件失败,就返回-1。如:$ awk ‘BEGIN{ “date” | getline d; print d}’ test。执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量d,并打印它。

      $ awk ‘BEGIN{“date” | getline d; split(d,mon); print mon[2]}’ test。执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给d,split函数把变量d转 化成数组mon,然后打印数组mon的第二个元素。

      $ awk ‘BEGIN{while( “ls” | getline) print}’,命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为 BEGIN块在打开输入文件前执行,所以可以忽略输入文件。

      $ awk ‘BEGIN{printf “What is your name?”; getline name < “/dev/tty” } $1 ~name {print “Found” name on line “, NR “.”} END{print “See you,” name “.”} test。在屏幕上打印”What is your name?”,并等待用户应答。当一行输入完毕后,getline函数从终端接收该行输入,并把它储存在自定义变量name中。如果第一个域匹配变量 name的值,print函数就被执行,END块打印See you和name的值。

      $ awk ‘BEGIN{while (getline < “/etc/passwd” > 0) lc++; print lc}’。awk将逐行读取文件/etc/passwd的内容,在到达文件末尾前,计数器lc一直增加,当到末尾时,打印lc的值。注意,如果文件不存 在,getline返回-1,如果到达文件的末尾就返回0,如果读到一行,就返回1,所以命令 while (getline < “/etc/passwd”)在文件不存在的情况下将陷入无限循环,因为返回-1表示逻辑真。

    • 可以在awk中打开一个管 道,且同一时刻只能有一个管道存在。通过close()可关闭管道。如:$ awk ‘{print $1, $2 | “sort” }’ test END {close(“sort”)}。awd把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作。
    • system函数可以在awk中执行linux的命令。如:$ awk ‘BEGIN{system(“clear”)’。
    • fflush函数用以刷新输出缓冲区,如果没有参数,就刷新标准输出的缓冲区,如果以空字符串为参数,如fflush(“”),则刷新所有文件和管道的输出缓冲区。

    14.5. 条件语句

    awk中的条件语句是从C语言中借鉴过来的,可控制程序的流程。

    14.5.1. if语句

    格式:
            {if (expression){
                       statement; statement; ...
                         }
            }

    $ awk ‘{if ($1 <$2) print $2 “too high”}’ test。如果第一个域小于第二个域则打印。

    $ awk ‘{if ($1 < $2) {count++; print “ok”}}’ test.如果第一个域小于第二个域,则count加一,并打印ok。

    14.5.2. if/else语句,用于双重判断。

    格式:
            {if (expression){
                       statement; statement; ...
                           }
            else{
                       statement; statement; ...
                           }
            }

    $ awk ‘{if ($1 > 100) print $1 “bad” ; else print “ok”}’ test。如果$1大于100则打印$1 bad,否则打印ok。

    $ awk ‘{if ($1 > 100){ count++; print $1} else {count–; print $2}’ test。如果$1大于100,则count加一,并打印$1,否则count减一,并打印$1。

    14.5.3. if/else else if语句,用于多重判断。

    格式:
            {if (expression){
                        statement; statement; ...
                       }
            else if (expression){
                        statement; statement; ...
                       }
            else if (expression){
                        statement; statement; ...
                       }
            else {
                       statement; statement; ...
                 }
            }

    14.6. 循环

    • awk有三种循环:while循环;for循环;special for循环。
    • $ awk ‘{ i = 1; while ( i <= NF ) { print NF,$i; i++}}’ test。变量的初始值为1,若i小于可等于NF(记录中域的个数),则执行打印语句,且i增加1。直到i的值大于NF.
    • $ awk ‘{for (i = 1; i<NF; i++) print NF,$i}’ test。作用同上。
    • breadkcontinue语句。break用于在满足条件的情况下跳出循环;continue用于在满足条件的情况下忽略后面的语句,直接返回循环的顶端。如:
      {for ( x=3; x<=NF; x++)
                  if ($x<0){print "Bottomed out!"; break}}
      {for ( x=3; x<=NF; x++)
                  if ($x==0){print "Get next item"; continue}}
    • next语句从输入文件中读取一行,然后从头开始执行awk脚本。如:
      {if ($1 ~/test/){next}
          else {print}
      }
    • exit语句用于结束awk程序,但不会略过END块。退出状态为0代表成功,非零值表示出错。

    14.7. 数组

    awk中的数组的下标可以是数字和字母,称为关联数组。

    14.7.1. 下标与关联数组

    • 用 变量作为数组下标。如:$ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}’ test。数组name中的下标是一个自定义变量x,awk初始化x的值为0,在每次使用后增加1。第二个域的值被赋给name数组的各个元素。在END 模块中,for循环被用于循环整个数组,从下标为0的元素开始,打印那些存储在数组中的值。因为下标是关健字,所以它不一定从0开始,可以从任何值开始。
    • special for循环用于读取关联数组中的元素。格式如下:
      {for (item in arrayname){
               print arrayname[item]
               }
      }

      $ awk ‘/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}’ test。打印有值的数组元素。打印的顺序是随机的。

    • 用字符串作为下标。如:count["test"]
    • 用 域值作为数组的下标。一种新的for循环方式,for (index_value in array) statement。如:$ awk ‘{count[$1]++} END{for(name in count) print name,count[name]}’ test。该语句将打印$1中字符串出现的次数。它首先以第一个域作数组count的下标,第一个域变化,索引就变化。
    • delete 函数用于删除数组元素。如:$ awk ‘{line[x++]=$1} END{for(x in line) delete(line[x])}’ test。分配给数组line的是第一个域的值,所有记录处理完成后,special for循环将删除每一个元素。

    14.8. awk的内建函数

    14.8.1. 字符串函数

    • sub函数匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的时候。格式如下:
                  sub (regular expression, substitution string):
                  sub (regular expression, substitution string, target string)

      实例:

                  $ awk '{ sub(/test/, "mytest"); print }' testfile
                  $ awk '{ sub(/test/, "mytest"); $1}; print }' testfile

      第一个例子在整个记录中匹配,替换只发生在第一次匹配发生的时候。如要在整个文件中进行匹配需要用到gsub

      第二个例子在整个记录的第一个域中进行匹配,替换只发生在第一次匹配发生的时候。

    • gsub函数作用如sub,但它在整个文档中进行匹配。格式如下:
                  gsub (regular expression, substitution string)
                  gsub (regular expression, substitution string, target string)

      实例:

                  $ awk '{ gsub(/test/, "mytest"); print }' testfile
                  $ awk '{ gsub(/test/, "mytest"), $1 }; print }' testfile

      第一个例子在整个文档中匹配test,匹配的都被替换成mytest。

      第二个例子在整个文档的第一个域中匹配,所有匹配的都被替换成mytest。

    • index函数返回子字符串第一次被匹配的位置,偏移量从位置1开始。格式如下:
                index(string, substring)

      实例:

                  $ awk '{ print index("test", "mytest") }' testfile

      实例返回test在mytest的位置,结果应该是3。

    • length函数返回记录的字符数。格式如下:
                  length( string )
                  length

      实例:

                  $ awk '{ print length( "test" ) }'
                  $ awk '{ print length }' testfile

      第一个实例返回test字符串的长度。

      第二个实例返回testfile文件中第条记录的字符数。

    • substr函数返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串。格式如下:
                  substr( string, starting position )
                  substr( string, starting position, length of string )

      实例:

                  $ awk '{ print substr( "hello world", 7,11 ) }'

      上例截取了world子字符串。

    • match函数返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位置,RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串。函数格式如下:
                  match( string, regular expression )

      实例:

                  $ awk '{start=match("this is a test",/[a-z]+$/); print start}'
                  $ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'

      第一个实例打印以连续小写字符结尾的开始位置,这里是11。

      第二个实例还打印RSTART和RLENGTH变量,这里是11(start),11(RSTART),4(RLENGTH)。

    • toupper和tolower函数可用于字符串大小间的转换,该功能只在gawk中有效。格式如下:
                  toupper( string )
                  tolower( string )

      实例:

                  $ awk '{ print toupper("test"), tolower("TEST") }'
    • split函数可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割。格式如下:
                  split( string, array, field separator )
                  split( string, array )

      实例:

                  $ awk '{ split( "20:18:00", time, ":" ); print time[2] }'

      上例把时间按冒号分割到time数组内,并显示第二个数组元素18。

    14.8.2. 时间函数

    • systime函数返回从1970年1月1日开始到当前时间(不计闰年)的整秒数。格式如下:
                  systime()

      实例:

                  $ awk '{ now = systime(); print now }'
    • strftime函数使用C库中的strftime函数格式化时间。格式如下:
                  systime( [format specification][,timestamp] )

      Table 3. 日期和时间格式说明符

      格式描述
      %a 星期几的缩写(Sun)
      %A 星期几的完整写法(Sunday)
      %b 月名的缩写(Oct)
      %B 月名的完整写法(October)
      %c 本地日期和时间
      %d 十进制日期
      %D 日期 08/20/99
      %e 日期,如果只有一位会补上一个空格
      %H 用十进制表示24小时格式的小时
      %I 用十进制表示12小时格式的小时
      %j 从1月1日起一年中的第几天
      %m 十进制表示的月份
      %M 十进制表示的分钟
      %p 12小时表示法(AM/PM)
      %S 十进制表示的秒
      %U 十进制表示的一年中的第几个星期(星期天作为一个星期的开始)
      %w 十进制表示的星期几(星期天是0)
      %W 十进制表示的一年中的第几个星期(星期一作为一个星期的开始)
      %x 重新设置本地日期(08/20/99)
      %X 重新设置本地时间(12:00:00)
      %y 两位数字表示的年(99)
      %Y 当前月份
      %Z 时区(PDT)
      %% 百分号(%)

      实例:

    • $ awk ‘{ now=strftime( “%D”, systime() ); print now }’

    • $ awk ‘{ now=strftime(“%m/%d/%y”); print now }’

    14.8.3. 内建数学函数

    Table 4.

    函数名称返回值
    atan2(x,y) y,x范围内的余切
    cos(x) 余弦函数
    exp(x) 求幂
    int(x) 取整
    log(x) 自然对数
    rand() 随机数
    sin(x) 正弦
    sqrt(x) 平方根
    srand(x) x是rand()函数的种子
    int(x) 取整,过程没有舍入
    rand() 产生一个大于等于0而小于1的随机数

    14.8.4. 自定义函数

    在awk中还可自定义函数,格式如下:

            function name ( parameter, parameter, parameter, ... ) {
                            statements
                            return expression                  # the return statement and expression are optional
            }

    15. How-to

    • 如何把一行竖排的数据转换成横排?awk ‘{printf(“%s,”,$1)}’ filename

    awk 实例

    awk 'sub(/utf8[^,]/, "utf8,usefree ")' ./wkl.log 1<>./wkl.log

    和sed一样,awk也是逐行扫描文件的,从第一行到最后一行,寻找匹配特定模板的行,并在这些行上运行“选择”动作。如果一个模板没有指定动作,这些匹配的行就被显示在屏幕上。如果一个动作没有模板,所有被动作指定的行都被处理。

    1. awk的基本格式:

    /> awk 'pattern' filename
    /> awk '{action}' filename
    /> awk 'pattern {action}' filename
    

    具体应用方式分别见如下三个用例:

    /> cat employees
    Tom Jones 4424 5/12/66 543354
    Mary Adams 5346 11/4/63 28765
    Sally Chang 1654 7/22/54 650000
    Billy Black 1683 9/23/44 336500
    
    /> awk '/Mary/' employees #打印所有包含模板Mary的行。
    Mary Adams 5346 11/4/63 28765
    

    #打印文件中的第一个字段,这个域在每一行的开始,缺省由空格或其它分隔符。

    /> awk '{print $1}' employees
    Tom
    Mary
    Sally
    Billy
    
    /> awk '/Sally/{print $1, $2}' employees #打印包含模板Sally的行的第一、第二个域字段。
    Sally Chang
    

    2. awk的格式输出:

    awk中同时提供了print和printf两种打印输出的函数,其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。下面给出基本的转码序列:

    转码 含义
    换行
    回车
    制表符
    /> date | awk '{print "Month: " $2 "
    Year: ", $6}'
    Month: Oct
    Year: 2011
    
    /> awk '/Sally/{print "		Have a nice day, " $1,$2 "!"}' employees
    Have a nice day, Sally Chang!
    

    在打印数字的时候你也许想控制数字的格式,我们通常用printf来完成这个功能。awk的特殊变量OFMT也可以在使用print函数的时候,控制数字的打印格式。它的默认值是"%.6g"----小数点后面6位将被打印。

    /> awk 'BEGIN { OFMT="%.2f"; print 1.2456789, 12E-2}'
    1.25 0.12
    

    现在我们介绍一下功能更为强大的printf函数,其用法和c语言中printf基本相似。下面我们给出awk中printf的格式化说明符列表:

    格式化说明符 功能 示例 结果
    %c 打印单个ASCII字符。 printf("The character is %c. ",x) The character is A.
    %d 打印十进制数。 printf("The boy is %d years old. ",y) The boy is 15 years old.
    %e 打印用科学记数法表示的数。 printf("z is %e. ",z) z is 2.3e+01.
    %f 打印浮点数。 printf("z is %f. ",z) z is 2.300000
    %o 打印八进制数。 printf("y is %o. ",y) y is 17.
    %s 打印字符串。 printf("The name of the culprit is %s. ",$1); The name of the culprit is Bob Smith.
    %x 打印十六进制数。 printf("y is %x. ",y) y is f.

    注:假设列表中的变脸值为x = A, y = 15, z = 2.3, $1 = "Bob Smith"

    /> echo "Linux" | awk '{printf "|%-15s|
    ", $1}' # %-15s表示保留15个字符的空间,同时左对齐。
    |Linux |
    
    /> echo "Linux" | awk '{printf "|%15s|
    ", $1}' # %-15s表示保留15个字符的空间,同时右对齐。
    | Linux|
    

    #%8d表示数字右对齐,保留8个字符的空间。

    /> awk '{printf "The name is %-15s ID is %8d
    ", $1,$3}' employees
    The name is Tom ID is 4424
    The name is Mary ID is 5346
    The name is Sally ID is 1654
    The name is Billy ID is 1683
    

    3. awk中的记录和域:

    awk中默认的记录分隔符是回车,保存在其内建变量ORS和RS中。$0变量是指整条记录。

    /> awk '{print $0}' employees #这等同于print的默认行为。
    Tom Jones 4424 5/12/66 543354
    Mary Adams 5346 11/4/63 28765
    Sally Chang 1654 7/22/54 650000
    Billy Black 1683 9/23/44 336500
    

    变量NR(Number of Record),记录每条记录的编号。

    /> awk '{print NR, $0}' employees
    1 Tom Jones 4424 5/12/66 543354
    2 Mary Adams 5346 11/4/63 28765
    3 Sally Chang 1654 7/22/54 650000
    4 Billy Black 1683 9/23/44 336500
    

    变量NF(Number of Field),记录当前记录有多少域。

    /> awk '{print $0,NF}' employees
    Tom Jones 4424 5/12/66 543354 5
    Mary Adams 5346 11/4/63 28765 5
    Sally Chang 1654 7/22/54 650000 5
    Billy Black 1683 9/23/44 336500 5
    

    #根据employees生成employees2。sed的用法可以参考上一篇blog。

    /> sed 's/[[:space:]]+([0-9])/:1/g;w employees2' employees
    /> cat employees
    Tom Jones:4424:5/12/66:543354
    Mary Adams:5346:11/4/63:28765
    Sally Chang:1654:7/22/54:650000
    Billy Black:1683:9/23/44:336500
    
    /> awk -F: '/Tom Jones/{print $1,$2}' employees2 #这里-F选项后面的字符表示分隔符。
    Tom Jones 4424
    

    变量OFS(Output Field Seperator)表示输出字段间的分隔符,缺省是空格。

    /> awk -F: '{OFS = "?"}; /Tom/{print $1,$2 }' employees2 #在输出时,域字段间的分隔符已经是?(问号)了
    Tom Jones?4424
    

    对于awk而言,其模式部分将控制这动作部分的输入,只有符合模式条件的记录才可以交由动作部分基础处理,而模式部分不仅可以写成正则表达式(如上面的例子),awk还支持条件表达式,如:

    /> awk '$3 < 4000 {print}' employees
    Sally Chang 1654 7/22/54 650000
    Billy Black 1683 9/23/44 336500
    

    在花括号内,用分号分隔的语句称为动作。如果模式在动作前面,模式将决定什么时候发出动作。动作可以是一个语句或是一组语句。语句之间用分号分隔,也可以用换行符,如:

    pattern { action statement; action statement; etc. } or
    pattern {
    action statement
    action statement
    }
    

    模式和动作一般是捆绑在一起的。需要注意的是,动作是花括号内的语句。模式控制的动作是从第一个左花括号开始到第一个右花括号结束,如下:

    /> awk '$3 < 4000 && /Sally/ {print}' employees
    Sally Chang 1654 7/22/54 650000

    4. 匹配操作符:

    " ~ " 用来在记录或者域内匹配正则表达式。

    /> awk '$1 ~ /[Bb]ill/' employees #显示所有第一个域匹配Bill或bill的行。
    Billy Black 1683 9/23/44 336500
    
    /> awk '$1 !~ /[Bb]ill/' employees #显示所有第一个域不匹配Bill或bill的行,其中!~表示不匹配的意思。
    Tom Jones 4424 5/12/66 543354
    Mary Adams 5346 11/4/63 28765
    Sally Chang 1654 7/22/54 650000
    

    5. awk的基本应用实例:

    /> cat testfile
    northwest NW Charles Main 3.0 .98 3 34
    western WE Sharon Gray 5.3 .97 5 23
    southwest SW Lewis Dalsass 2.7 .8 2 18
    southern SO Suan Chin 5.1 .95 4 15
    southeast SE Patricia Hemenway 4.0 .7 4 17
    eastern EA TB Savage 4.4 .84 5 20
    northeast NE AM Main Jr. 5.1 .94 3 13
    north NO Margot Weber 4.5 .89 5 9
    central CT Ann Stephens 5.7 .94 5 13
    
    /> awk '/^north/' testfile #打印所有以north开头的行。
    northwest NW Charles Main 3.0 .98 3 34
    northeast NE AM Main Jr. 5.1 .94 3 13
    north NO Margot Weber 4.5 .89 5 9
    
    /> awk '/^(no|so)/' testfile #打印所有以so和no开头的行。
    northwest NW Charles Main 3.0 .98 3 34
    southwest SW Lewis Dalsass 2.7 .8 2 18
    southern SO Suan Chin 5.1 .95 4 15
    southeast SE Patricia Hemenway 4.0 .7 4 17
    northeast NE AM Main Jr. 5.1 .94 3 13
    north NO Margot Weber 4.5 .89 5 9
    
    /> awk '$5 ~ /.[7-9]+/' testfile #第五个域字段匹配包含.(点),后面是7-9的数字。
    southwest SW Lewis Dalsass 2.7 .8 2 18
    central CT Ann Stephens 5.7 .94 5 13
    
    /> awk '$8 ~ /[0-9][0-9]$/{print $8}' testfile #第八个域以两个数字结束的打印。
    34
    23
    18
    15
    17
    20
    13
    

    十. awk表达式功能:

    1. 比较表达式:

    比较表达式匹配那些只在条件为真时才运行的行。这些表达式利用关系运算符来比较数字和字符串。见如下awk支持的条件表达式列表:

    运算符 含义 例子
    < 小于 x < y
    <= 小于等于 x <= y
    == 等于 x == y
    != 不等于 x != y
    >= 大于等于 x >= y
    > 大于 x > y
    ~ 匹配 x ~ /y/
    !~ 不匹配 x !~ /y/
    /> cat employees
    Tom Jones 4424 5/12/66 543354
    Mary Adams 5346 11/4/63 28765
    Sally Chang 1654 7/22/54 650000
    Billy Black 1683 9/23/44 336500
    
    /> awk '$3 == 5346' employees #打印第三个域等于5346的行。
    Mary Adams 5346 11/4/63 28765
    
    /> awk '$3 > 5000 {print $1}' employees #打印第三个域大于5000的行的第一个域字段。
    Mary
    
    /> awk '$2 ~ /Adam/' employess #打印第二个域匹配Adam的行。
    Mary Adams 5346 11/4/63 28765
    

    2. 条件表达式:

    条件表达式使用两个符号--问号和冒号给表达式赋值: conditional expression1 ? expression2 : expressional3,其逻辑等同于C语言中的条件表达式。其对应的if/else语句如下:

    {
    if (expression1)
    expression2
    else
    expression3
    }
    /> cat testfile
    northwest NW Charles Main 3.0 .98 3 34
    western WE Sharon Gray 5.3 .97 5 23
    southwest SW Lewis Dalsass 2.7 .8 2 18
    southern SO Suan Chin 5.1 .95 4 15
    southeast SE Patricia Hemenway 4.0 .7 4 17
    eastern EA TB Savage 4.4 .84 5 20
    northeast NE AM Main Jr. 5.1 .94 3 13
    north NO Margot Weber 4.5 .89 5 9
    central CT Ann Stephens 5.7 .94 5 13
    
    /> awk 'NR <= 3 {print ($7 > 4 ? "high "$7 : "low "$7) }' testfile
    low 3
    high 5
    low 2
    

    3. 数学表达式:

    运算可以在模式内进行,其中awk将所有的运算都视为浮点运算,见如下列表:

    运算符 含义 例子
    + x + y
    - x - y
    * x * y
    / x / y
    % 取余 x % y
    ^ 乘方 x ^ y
    /> awk '/southern/{print $5 + 10}' testfile #如果记录包含正则表达式southern,第五个域就加10并打印。
    15.1
    
    /> awk '/southern/{print $8 /2 }' testfile #如果记录包含正则表达式southern,第八个域除以2并打印。
    7.5
    

    4. 逻辑表达式:

    见如下列表:

    运算符 含义 例子
    && 逻辑与 a && b
    || 逻辑或 a || b
    ! 逻辑非 !a
    /> awk '$8 > 10 && $8 < 17' testfile #打印出第八个域的值大于10小于17的记录。
    southern SO Suan Chin 5.1 .95 4 15
    central CT Ann Stephens 5.7 .94 5 13
    

    #打印第二个域等于NW,或者第一个域匹配south的行的第一、第二个域。

    /> awk '$2 == "NW" || $1 ~ /south/ {print $1,$2}' testfile
    northwest NW
    southwest SW
    southern SO
    southeast SE
    
    /> awk '!($8 > 13) {print $8}' testfile #打印第八个域字段不大于13的行的第八个域。
    3
    9
    13
    

    5. 范围模板:

    范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现,第一个模板的下一次出现到第一个模板的下一次出现等等。如果第一个模板匹配而第二个模板没有出现,awk就显示到文件末尾的所有行。

    /> awk '/^western/,/^eastern/ {print $1}' testfile #打印以western开头到eastern开头的记录的第一个域。
    western WE
    southwest SW
    southern SO
    southeast SE
    eastern EA
    

    6. 赋值符号:

    #找到第三个域等于Ann的记录,然后给该域重新赋值为Christian,之后再打印输出该记录。

    /> awk '$3 == "Ann" { $3 = "Christian"; print}' testfile
    central CT Christian Stephens 5.7 .94 5 13
    
    /> awk '/Ann/{$8 += 12; print $8}' testfile #找到包含Ann的记录,并将该条记录的第八个域的值+=12,最后再打印输出。
    25
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    Linux awk 命令 说明
     
     
     
     
      
     
    一.  AWK 说明
     
           awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。
     
           awk的处理文本和数据的方式:它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。
     
           awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。
     
           gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。
     
      
     
    二. awk命令格式和选项
     
    2.1. awk的语法有两种形式
     
           awk [options] 'script' var=value file(s)
     
           awk [options] -f scriptfile var=value file(s)
     
      
     
    2.2. 命令选项
     
    (1)-F fs or --field-separator fs :指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。
     
    (2)-v var=value or --asign var=value :赋值一个用户定义变量。
     
    (3)-f scripfile or --file scriptfile :从脚本文件中读取awk命令。
     
    (4)-mf nnn and -mr nnn :对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
     
    (5)-W compact or --compat, -W traditional or --traditional :在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
     
    (6)-W copyleft or --copyleft, -W copyright or --copyright :打印简短的版权信息。
     
    (7)-W help or --help, -W usage or --usage :打印全部awk选项和每个选项的简短说明。
     
    (8)-W lint or --lint :打印不能向传统unix平台移植的结构的警告。
     
    (9)-W lint-old or --lint-old :打印关于不能向传统unix平台移植的结构的警告。
     
    (10)-W posix :打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。
     
    (11)-W re-interval or --re-inerval :允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
     
    (12)-W source program-text or --source program-text :使用program-text作为源代码,可与-f命令混用。
     
    (13)-W version or --version :打印bug报告信息的版本。
     
      
     
    三. 模式和操作
     
    awk脚本是由模式和操作组成的:
     
                  pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test。
     
           两者是可选的,如果没有模式,则action应用到全部记录,如果没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。
     
      
     
    3.1. 模式
     
    模式可以是以下任意一个:
     
    (1)正则表达式:使用通配符的扩展集。
     
    (2)关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符(3)串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。
     
    (4)模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
     
    (5)模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。
     
    (6)BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。
     
    (7)END:让用户在最后一条输入记录被读取之后发生的动作。
     
      
     
    3.2. 操作
     
           操作由一人或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内。主要有四部份:
     
    (1)变量或数组赋值
     
    (2)输出命令
     
    (3)内置函数
     
    (4)控制流命令
     
      
     
    四. awk的环境变量
     
     
    变量
      
    描述
      
     
     
    $n
      
    当前记录的第n个字段,字段间由FS分隔。
      
     
    $0
      
    完整的输入记录。
      
     
    ARGC
      
    命令行参数的数目。
      
     
    ARGIND
      
    命令行中当前文件的位置(从0开始算)。
      
     
    ARGV
      
    包含命令行参数的数组。
      
     
    CONVFMT
      
    数字转换格式(默认值为%.6g)
      
     
    ENVIRON
      
    环境变量关联数组。
      
     
    ERRNO
      
    最后一个系统错误的描述。
      
     
    FIELDWIDTHS
      
    字段宽度列表(用空格键分隔)。
      
     
    FILENAME
      
    当前文件名。
      
     
    FNR
      
    同NR,但相对于当前文件。
      
     
    FS
      
    字段分隔符(默认是任何空格)。
      
     
    IGNORECASE
      
    如果为真,则进行忽略大小写的匹配。
      
     
    NF
      
    当前记录中的字段数。
      
     
    NR
      
    当前记录数。
      
     
    OFMT
      
    数字的输出格式(默认值是%.6g)。
      
     
    OFS
      
    输出字段分隔符(默认值是一个空格)。
      
     
    ORS
      
    输出记录分隔符(默认值是一个换行符)。
      
     
    RLENGTH
      
    由match函数所匹配的字符串的长度。
      
     
    RS
      
    记录分隔符(默认是一个换行符)。
      
     
    RSTART
      
    由match函数所匹配的字符串的第一个位置。
      
     
    SUBSEP
      
    数组下标分隔符(默认值是/034)。
      
     
      
     
    五. awk运算符
     
      
     
     
    运算符
      
    描述
      
     
     
    = += -= *= /= %= ^= **=
      
    赋值
      
     
    ?:
      
    C条件表达式
      
     
    ||
      
    逻辑或
      
     
    &&
      
    逻辑与
      
     
    ~ ~!
      
    匹配正则表达式和不匹配正则表达式
      
     
    < <= > >= != ==
      
    关系运算符
      
     
    空格
      
    连接
      
     
    + -
      
    加,减
      
     
    * / &
      
    乘,除与求余
      
     
    + - !
      
    一元加,减和逻辑非
      
     
    ^ ***
      
    求幂
      
     
    ++ --
      
    增加或减少,作为前缀或后缀
      
     
    $
      
    字段引用
      
     
    in
      
    数组成员
      
     
      
     
    六. 记录和域
     
    6.1. 记录
     
           awk把每一个以换行符结束的行称为一个记录。
     
           记录分隔符:默认的输入和输出的分隔符都是回车,保存在内建变量ORS和RS中。
     
           $0变量:它指的是整条记录。如$ awk '{print $0}' test将输出test文件中的所有记录。
     
           变量NR:一个计数器,每处理完一条记录,NR的值就增加1。
     
           如$ awk '{print NR,$0}' test将输出test文件中所有记录,并在记录前显示记录号。
     
      
     
    6.2. 域
     
           记录中每个单词称做“域”,默认情况下以空格或tab分隔。awk可跟踪域的个数,并在内建变量NF中保存该值。如$ awk '{print $1,$3}' test将打印test文件中第一和第三个以空格分开的列(域)。
     
      
     
    6.3. 域分隔符
     
           内建变量FS保存输入域分隔符的值,默认是空格或tab。我们可以通过-F命令行选项修改FS的值。如$ awk -F: '{print $1,$5}' test将打印以冒号为分隔符的第一,第五列的内容。
     
           可以同时使用多个域分隔符,这时应该把分隔符写成放到方括号中,如$awk -F'[:/t]' '{print $1,$3}' test,表示以空格、冒号和tab作为分隔符。
     
           输出域的分隔符默认是一个空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5间的逗号就是OFS的值。
     
      
     
    七. gawk专用正则表达式元字符
     
      
     
    以下几个是gawk专用的,不适合unix版本的awk。
     
    (1)/Y :匹配一个单词开头或者末尾的空字符串。
     
    (2)/B:匹配单词内的空字符串。
     
    (3)/<:匹配一个单词的开头的空字符串,锚定开始。
     
    (4)/> :匹配一个单词的末尾的空字符串,锚定末尾。
     
    (5)/w :匹配一个字母数字组成的单词。
     
    (6)/W :匹配一个非字母数字组成的单词。
     
    (7)/‘:匹配字符串开头的一个空字符串。
     
    (8)/' :匹配字符串末尾的一个空字符串。
     
      
     
    八. 匹配操作符(~)
     
           用来在记录或者域内匹配正则表达式。如$ awk '$1 ~/^root/' test将显示test文件第一列中以root开头的行。
     
      
     
    九. 比较表达式
     
    conditional expression1 ? expression2: expression3,
     
    例如:$ awk '{max = {$1 > $3} ? $1: $3: print max}' test。如果第一个域大于第三个域,$1就赋值给max,否则$3就赋值给max。
     
    $ awk '$1 + $2 < 100' test。如果第一和第二个域相加大于100,则打印这些行。
     
    $ awk '$1 > 5 && $2 < 10' test,如果第一个域大于5,并且第二个域小于10,则打印这些行。
     
      
     
    十. 范围模板
     
           范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现之间所有行。如果有一个模板没出现,则匹配到开头或末尾。如$ awk '/root/,/mysql/' test将显示root第一次出现到mysql第一次出现之间的所有行。
     
      
     
    十一. 示例
     
      
     
    1、awk '/101/' file 显示文件file中包含101的匹配行。
    awk '/101/,/105/' file
    awk '$1 == 5' file
    awk '$1 == "CT"' file 注意必须带双引号
    awk '$1 * $2 >100 ' file
    awk '$2 >5 && $2<=15' file
     
     
    2、awk '{print NR,NF,$1,$NF,}' file 显示文件file的当前记录号、域数和每一行的第一个和最后一个域。
    awk '/101/ {print $1,$2 + 10}' file 显示文件file的匹配行的第一、二个域加10。
    awk '/101/ {print $1$2}' file
    awk '/101/ {print $1 $2}' file 显示文件file的匹配行的第一、二个域,但显示时域中间没有分隔符。
     
     
    3、df | awk '$4>1000000 ' 通过管道符获得输入,如:显示第4个域满足条件的行。
     
     
    4、awk -F "|" '{print $1}' file 按照新的分隔符“|”进行操作。
    awk 'BEGIN { FS="[: /t|]" }
    {print $1,$2,$3}' file 通过设置输入分隔符(FS="[: /t|]")修改输入分隔符。
    Sep="|"
    awk -F $Sep '{print $1}' file 按照环境变量Sep的值做为分隔符。
    awk -F '[ :/t|]' '{print $1}' file 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。
    awk -F '[][]' '{print $1}' file 按照正则表达式的值做为分隔符,这里代表[、]
     
     
    5、awk -f awkfile file 通过文件awkfile的内容依次进行控制。
    cat awkfile
    /101/{print "/047 Hello! /047"} --遇到匹配行以后打印 ' Hello! './047代表单引号。
    {print $1,$2} --因为没有模式控制,打印每一行的前两个域。
     
     
     
    6、awk '$1 ~ /101/ {print $1}' file 显示文件中第一个域匹配101的行(记录)。
     
     
     
    7、awk 'BEGIN { OFS="%"}
    {print $1,$2}' file 通过设置输出分隔符(OFS="%")修改输出格式。
     
     
     
    8、awk 'BEGIN { max=100 ;print "max=" max}
     
           BEGIN 表示在处理任意行之前进行的操作。
    {max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得文件第一个域的最大值。
     
      
     
    9、awk '$1 * $2 >100 {print $1}' file 显示文件中第一个域匹配101的行(记录)。
     
     
     
    10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 找到匹配行后先将第3个域替换后再显示该行(记录)。
    awk '{$7 %= 3; print $7}' file 将第7域被3除,并将余数赋给第7域再打印。
     
     
     
    11、awk '/tom/ {wage=$2+$3; printf wage}' file 找到匹配行后为变量wage赋值并打印该变量。
     
     
     
    12、awk '/tom/ {count++;}
    END {print "tom was found "count" times"}' file
     
      
     
    END表示在所有输入行处理完后进行处理。
     
     
     
    13、awk 'gsub(//$/,"");gsub(/,/,""); cost+=$4;
    END {print "The total is $" cost>"filename"}' file
     
           gsub函数用空串替换$和,再将结果输出到filename中。
    1 2 3 $1,200.00
    1 2 3 $2,300.00
    1 2 3 $4,000.00
     
    awk '{gsub(//$/,"");gsub(/,/,"");
    if ($4>1000&&$4<2000) c1+=$4;
    else if ($4>2000&&$4<3000) c2+=$4;
    else if ($4>3000&&$4<4000) c3+=$4;
    else c4+=$4; }
    END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]/n",c1,c2,c3,c4}"' file
    通过if和else if完成条件语句
     
    awk '{gsub(//$/,"");gsub(/,/,"");
    if ($4>3000&&$4<4000) exit;
    else c4+=$4; }
    END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]/n",c1,c2,c3,c4}"' file
     
    通过exit在某条件时退出,但是仍执行END操作。
     
     
     
    awk '{gsub(//$/,"");gsub(/,/,"");
    if ($4>3000) next;
    else c4+=$4; }
    END {printf "c4=[%d]/n",c4}"' file
    通过next在某条件时跳过该行,对下一行执行操作。
     
    14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall
     
           把file1、file2、file3的文件内容全部写到fileall中,格式为打印文件并前置文件名。
     
      
     
    15、awk ' $1!=previous { close(previous); previous=$1 }
    {print substr($0,index($0," ") +1)>$1}' fileall
     
           把合并后的文件重新分拆为3个文件。并与原文件一致。
     
      
     
    16、awk 'BEGIN {"date"|getline d; print d}'
     
           通过管道把date的执行结果送给getline,并赋给变量d,然后打印。
     
      
     
    17、awk 'BEGIN {system("echo "Input your name://c""); getline d;print "/nYour name is",d,"/b!/n"}'
           通过getline命令交互输入name,并显示出来。
     
     
     
           awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]_") print $1}}'
           打印/etc/passwd文件中用户名包含050x_的用户名。
     
    18、awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file  通过while语句实现循环。
           awk '{ for(i=1;i<NF;i++) {print NF,$i}}' file 通过for语句实现循环。
     
     
    type file|awk -F "/" '
    { for(i=1;i<NF;i++)
    { if(i==NF-1) { printf "%s",$i }
    else { printf "%s/",$i } }}'
     
    显示一个文件的全路径。
     
     
    用for和if显示日期
    awk 'BEGIN {
    for(j=1;j<=12;j++)
    { flag=0;
    printf "/n%d月份/n",j;
    for(i=1;i<=31;i++)
    {
    if (j==2&&i>28) flag=1;
    if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
    if (flag==0) {printf "%02d%02d ",j,i}
    }
    }
    }'
     
     
    19、在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
    Flag=abcd
    awk '{print '$Flag'}' 结果为abcd
    awk '{print "$Flag"}' 结果为$Flag
     
      
     
    20. 其他小示例
     
    $ awk '/^(no|so)/' test-----打印所有以模式no或so开头的行。
     
    $ awk '/^[ns]/{print $1}' test-----如果记录以n或s开头,就打印这个记录。
     
    $ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果第一个域以两个数字结束就打印这个记录。
     
    $ awk '$1 == 100 || $2 < 50' test-----如果第一个或等于100或者第二个域小于50,则打印该行。
     
    $ awk '$1 != 10' test-----如果第一个域不等于10就打印该行。
     
    $ awk '/test/{print $1 + 10}' test-----如果记录包含正则表达式test,则第一个域加10并打印出来。
     
    $ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test-----如果第一个域大于5则打印问号后面的表达式值,否则打印冒号后面的表达式值。
     
    $ awk '/^root/,/^mysql/' test----打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾。
  • 相关阅读:
    [BZOJ 4034][HAOI2015]树上操作(欧拉序列+线段树)
    [BZOJ 4318]OSU!(期望dp)
    [Codeforces Round #146 (Div. 1) B]Let's Play Osu!(期望Dp)
    [Codeforces Round #261 (Div. 2) E]Pashmak and Graph(Dp)
    [Codeforces Round #301 (Div. 2) D]Bad Luck Island(概率Dp)
    [Codeforces Round #284 (Div. 1) B]Name That Tune(概率Dp)
    [UVALive 7143]Room Assignment(Dp)
    [BZOJ 1076][SCOI2008]奖励关(期望+状压Dp)
    【DBMS HKUST slides8】范式及分解算法 知识点总结
    【DBMS HKUST slides1~6】数据库管理系统 知识点总结
  • 原文地址:https://www.cnblogs.com/chengjian-physique/p/7923895.html
Copyright © 2020-2023  润新知