添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
BEGIN 之前就被定义,可以在 BEGIN 中使用。但 -v 必须先于文件名参数和程序文本。

如果在程序文本之后, awk '{ print $n }' n=4 inventory-shipped n=2 mail-list ,那么变量n会在读取每条记录时被赋值,会先打印文件 inventory-shipped 第四列的内容,然后打印文件 mail-list 第二列中的内容。

Predefined Variables

少数变量是有特殊含义的,它们是 predefined variables。这些变量,要么被 awk 自动检查(User-modified),要么被自动设置(Auto-set)。

User-modified

  • CONVFMT:控制数字到 string 转换。
  • FS:列分隔符,值为一个字符或匹配多个字符的正则表达式。 默认是 " " ,会匹配任何 \" ", \t, \n 。同时会使得每条记录开头和结尾的 " ", \t, \n 被忽略。
  • OFS:输出文件列分隔符。
  • ORS:输出文件记录分隔符(行尾)。
  • RS:输入文件记录分隔符(行尾)。
  • SUBSEP:下标分隔符,默认是 \034
  • Auto-set

  • ARGC, ARGV:awk 参数信息,ARGV 的起始下标为0。程序文本不会被包含到这两个变量中。
  • ENVIRON:关联数组,包含了 environment 的值。
  • FILENAME:当前输入文件的文件名。 未设置输入文件(stdin输入)时,值为 "-" ;在BEGIN中时,值为 ""
  • FNR:当前文件的行号,在每次打开新文件时被重置为0。
  • NF:当前记录的列数。在每读取一个新纪录的时候,或者 $0 改变的时候,被重置。
  • NR:已处理的行数。
  • RLENGTH:被 match() 匹配后,substring 的长度,没有匹配值为-1。
  • RSTART:被 match() 匹配后,substring 的起始位置,没有匹配值为0。
  • Pattern Elements

    Regexp Patterns

    awk 中正则表达式的形式为 /regexp/

    Expression Patterns

    awk 表达式都可作为一个 pattern,如果表达式的值非空或非零,那么就是匹配上了。常见的是由比较运算符构成的,

  • awk '$1 == "li" { print $2 }' mail-list 用于直接比较 string 的操作符除了 == ,还可以是 <, <=, >, >=, ==, != 。以及判断array中是否有以subscript为下表的元素,subscript in array。

  • awk '$1 ~ /li/ { print $2 }' mail-list 用于判断特定的 string 是否 match 正则表达式,需要用 ~, !~ 连接左右操作数。

  • awk '/edu/ && /li/' mail-list 也可以用布尔操作符连接正则表达式、由比较运算符构成的表达式,以及任何其他的 awk 表达式。

  • Ranges

    range pattern 由逗号分隔的两 个pattern 构成, begpat, endpat ,用于匹配连续的记录。 当遇到匹配 begpat 的记录时,开始匹配包括这条记录在内的所有后续记录,直到遇到匹配 endpat 的记录时,停止匹配,然后开始下一轮。如果有某条记录使得两个 pattern 都为 true,那么只匹配一次,并开始下一轮。

    1
    2
    3
    4
    5
    6
    7
    8
    file:
    awefawef
    aweawef%
    awefawfe
    aweawef%

    awk '/%$/,/%$/ {print}' test
    aweawef%

    BEGIN/END

    前面的几个 pattern 都是会匹配输入的, BEGIN/END 是特殊的 pattern,不会匹配(因为在它们执行的时候还没有记录,或者已经没有记录存在了),它们指定了 awk 程序起始和结束时的 action,都只会执行一次。

    如果存在多个 BEGIN/END ,那么按定义的顺序执行。 当仅有 BEGIN ,执行完 BEGIN 后,程序结束;当仅有 END ,程序会读取输入,然后执行 END

    常用awk程序

    下面是我常用到的,或者看到觉得不错的awk程序。

    以某个字符串为key,统计对应的value总和

    1
    awk '{a[$4"\t"$5"\t"$2]+=$3} END {for (x in a) print x"\t"a[x]}' $geo_file_ret | sort -k 4 -n -r > $1

    打印非空行

    1
    awk 'NF'

    因为 NF 是当前输入的列数,非空行的列数大于0。当条件为真,且没有其他的 action 时,awk执行默认操作,打印一行。扩展来说,可以只提供表达式,作为条件,表达式为真则打印响应行。

    1
    awk '!a[$0]++'

    a 是数组,每个元素被初始化为0, $0 作为索引。首次遇到的行, ++ 对以 $0 为下标的元素加1,后缀 ++ 返回原始值0,取反后为真,打印。后续如果再遇到相同的,可以取到一个非0的值,取反为false,不打印。因此实际上是去除了重复的行。

    1
    seq 1 30 | awk 'ORS=NR%5?FS:RS'

    默认情况下,ORS是一个换行符 "\n\" 。这里根据,已处理行数是否是5的倍数,为ORS赋值FS或RS,默认即, " " or "\n" 。它们的值都不为0,作为条件都是true。因此每一行都会打印,只是被打印行的行为分隔符是FS或RS。

    1
    2
    3
    4
    5
    6
    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

    替换分隔符

    在没有修改的情况下,awk 并不会重新 build $0 ,原因之一是,为了性能;二是,对于 echo 'foo;bar' | awk -v FS=';' -v OFS=',' '/foo/' ,如果真的替换了,那 foo,bar 并不是期望匹配到的 foo;bar 。 因此,不同于上面的 ORS,这里直接指定 FS 以及 OFS 是没有用的。

    1
    awk -v FS=';' -v OFS=',' '{$1=$1}1'

    这里的确修改了 $0 ,但内容没有变,因此会替换FS。如果没有空行,可以把1去除。

    连接字符串

    利用 awk 中变量被初始化为空 string 或0这一点,可以方便的连接字符串

    1
    string = string sep somedata; sep = ";"

    避免开头出现多余的 ";"

    处理两个文件

    当处理两个文件时,awk 按命令中指定的顺序,顺序读取每个文件。当读取第一个文件时, NR == FNR 总为true。 基于这点,有一个常用的写法,

    1
    awk 'NR == FNR { # some actions; next} # other condition {# other actions}' file1.txt file2.txt

    常用的场景比如,

  • 两文件的交集, awk 'NR == FNR{a[$0];next} $0 in a' file1.txt file2.txt
  • 两文件的差集(仅在第一个文件里出现), awk 'NR == FNR{a[$0];next} $0 in a' file1.txt file2.txt
  • 基于某一列,join两文件, awk 'NR == FNR{a[$1]=$2;next} {$3=a[$3]}1' map.txt data.txt
  • 不过这个写法,仅适用于第一个文件非空的情况,如果为空,会直接用 NR == FNR { # some actions; next} 处理第二个文件,可以检测FILENAME是否等于ARGV[1]。

  • http://coolshell.cn/articles/9070.html
  • http://www.gnu.org/software/gawk/manual/gawk.html
  •