awk

awk

awk是最有用的shell工具之一,名字的来源是三位工程师的名字首字母。

image.png

awk introduction

awk主要被用在文字和字符处理领域,作为一个通用的可编程过滤器。

awk面向域(field)而sed面向行(line),awk支持以文件、重定向、管道和标准输入作为程序的输入。
更准确的来讲,awk是一种仅需几行代码就能够处理复杂任务的编程语言,和sed一样,它是一种pattern-action语言,看起来和C语言类似,但是比C语言简单,它能够自动处理输入、域分割、初始化和内存管理等。

awk相比较于sed的特色:

  • 方便的数字处理
  • 在action中的变量和控制流
  • 更便于访问行中的域
  • 灵活的输出
  • 内置丰富的算术和字符串函数
  • 类C风格

awk的程序结构

一段awk程序包括:

  • 一段可选的BEGIN语句块(主要用于做一些预处理)
  • 一些pattern-action组合
  • 一段可选的END语句块(主要用于做一些后处理)
1
2
3
4
5
BEGIN {action}
pattern {action}
...
pattern {action}
END {action}

有几种方式运行一段awk程序:
a. awk ‘program’ input_files
b. awk ‘program’ 标准输入作为程序输入
c. awk -f ‘program_files’ input_files

pattern & action

awk从一系列输入文件中去搜索指定的pattern,然后执行特定的action当在遇到包含特定pattern的行或者域。
awk不会修改输入文件,一次只处理一行。

一个awk程序至少有一个pattern或者action

  • 默认的pattern是匹配所有的lines
  • 默认的action是打印当前的record
  • action包含在{}内,而pattern直接列出。

patterns

pattern是一个决定是否后面action是否被执行的选择器。
pattern可以是:

  • 特殊测token,例如BEGIN和END
  • 正则表达式 包含在//里面 例如 /[a-z]/
  • 字符串匹配表达式
  • !表达式取反
  • 以及通过&& 、|| 链接符连接的上述任意表达式
    • /NYU/
    • x > 0
    • /NYU/ && (name == ‘UNIX Tools’)

特殊的pattern token

  • BEGIN:预处理,常用于初始化一些内置变量例如FS、RS等;
  • END:后处理

actions

action可能包含一系列的类C的代码语句,执行一些类似算术、字符串表达式、声明以及输出。
action当每一行匹配一个pattern就会被执行,如果不指定pattern,action无条件执行,如果action不被指定,默认action是输出到标准设备。

例子:

1
2
3
4
ls|awk 'BEGIN {print "List all C language source files."}
/\.c$/ {print}
END {print "List has been done!"}
'

varaibles

作为一门语言,那么awk脚本当然可以定义和使用变量。
例如:

1
2
3
BEGIN {sum = 0}
{sum ++}
END {print sum}

后面会介绍到,awk预定义了一些有用变量。

records

预定义变量:

  • RS Record Separator
  • NR Number of Records

默认record seprator是newline,默认的awk一次处理一行。
RS可以是任意正则表达式,可以在BEGIN action中更改。

1
cat temp.txt|awk '{print "#"NR, $0}'

上面的$0表示该记录的第0个域,$开头的数字变量都表示域编号。

fields

预定义变量:

  • NF:Number of Field
  • FS:Filed Separator

输入中的每一行都按域分隔符被拆分。

  • awk预定义变量FS Filed Separator默认是空格(一个或多个空格或者tab)
  • awk -Fc可以设置FS为字符c
  • $0是当前所有行
  • $1是第一个域….,$NF是最后一个域,以此类推
    • {print $(NF-2)} 倒数第三个域
  • 计算和打印
    • {print $1, $2*$3}

默认的由”,”连接的项会被print打印为由单个空格连接的项。

格式化输出:

  • printf(fmt, val1, val2, …)
  • {printf(“%-8s %6.2f\n”, $1, $2)}

selectoins

前面提到awk是用作一个可编程的过滤器,用于处理文本和字符串。
除了前面提到的pattern(正则、begin&end等),更有用的的awk pattern还可以是如下这样的表达式pattern:

  • 比较: $2 >= 50 {print}
  • 计算: $2 * $3 > 50 {printf(“%6.2f “, $1)}
  • 文本内容:
    • $1 == “NYU”
    • $2 ~ /NYU/
  • 模式组合: $2 >= 4 || $3 >= 20
  • 行号 NR >= 10 && NR <= 20
  • ….
computings

awk可以方便的对域进行一些基本的计算,例如:

  • counting
1
2
$3 > 15 {emp = emp + 1}
END {printf("%d empoyess worked more than 15 hours.", emp)}
  • average and sum
1
2
3
4
{pay = pay + $2 * $3}
END {print NR, "employes"
print "total pay is ", pay
print "average pay is ", pay / NR}

strings manipulation

awk内置一些函数,用于处理字符串。

  • length(s)
  • substr(s,m,n)
1
2
3
4
5
6
{nc = nc + length($0) + 1
nw = nw + NF}
END {
print NR, "lines"
print nc, "chars"
print nw, "words"}

control flow

awk作为一门编程语言,提供几种基本的类C的流程控制结构。

  • IF THEN ELSE结构
1
2
3
4
5
6
7
$2 > 6 { n = n + 1}
END {
if (n > 0 }
print n
else
print "no employes."
}
  • WHILE
  • DO WHILE
  • FOR
1
2
for (i = 1; i < 10; i = i + 1)
print i

array

  • array下标可以是数字和字符串,当下标是字符串的时候,可以当一个map使用
  • example:a[“tom”] = 0.3

数组遍历:

1
2
for (k in array) {
print k, "==>", array[k]}

awk predefined variales

  • $0 $1 $2 $NF
  • NF NR NF
  • FS RS
  • FILENAME
  • OFS:output field separator default is single space

built-in functions

  • arithmetic
    • sin, cos, tan, exp, log, sqrt
  • strings
    • length, substr, split
  • output
    • print, printf
  • special
    • system(“cmd”) eg: system(“clear”)
    • exit -直接跳转到ENDpattern-action块

code snippets

  1. filter blank lines while you want to count your code
1
cat /path/to/yourcode/*.py | awk NF | wc -l

因为NF表示Number of Filed,默认的FS为空格,当awk遇见空行的时候,作为pattern的NF值为0,因此该行不会被输出。