命令格式
awk option 'function(...){} pattern {action}' input_file
option
这里列举一些常用的option:
-
-F 指定分隔符,比如以冒号(:)作为字段分隔符,并打印
/etc/passwd
文件的每行的第一个字段。-
awk -F: '{print $1}' /etc/passwd
-
-
-v 为自定义变量赋值
-
awk -v name="yuhan" '{print name}' filename
-
-
-f 指定一个包含
awk
脚本的文件,而不是在命令行中直接写出脚本。-
awk -f script.awk input_file
-
内置变量
这里列举一些常用的内置变量:
- RS:record separator,默认是换行符
- FS:field separator,每个record会被FS分割成多个field,默认是空格和制表符的任意组合
- NR:number of record,到现在为止读入了的record数量,常用来标记行号
- NF:record中field的数量
Pattern
awk的pattern有下面几种模式:
-
BEGIN
:一个特殊的模式,用于执行awk
开始读取输入之前的操作。 -
END
:另一个特殊的模式,用于在awk
处理完所有输入行后执行操作。 -
/regular expression/
:用于匹配输入行的正则表达式或条件表达式。 -
条件表达式
:<, <=, >, >=, ==, !=- 比如,从第二行开始输出第二列的值
-
awk 'NR > 1 {print $2}' data.txt
Action
{action}
定义当模式匹配时执行的命令或操作。
包括操作符和一些内置函数
操作符
$
Field 引用 $0, $1, $2...
~,!~
这两种操作符后跟正则表达式,代表匹配/不匹配后面的正则表达式,例如
$1 ~ /foo/
还有的操作符和其他语言中的类似,就不在这里列出了
控制语句
if () {} else {}
while () {}
do {} while()
for (exp1; exp2; exp3) {}
for (key in arr) {}
break
continue
delete arr[index]
delete arr # 删除所有元素,但不删除数组本身
exit [experssion] # 退出
使用exit的例子:
awk -F, '{if($2 ~ /foo/){exit 0}} END{print "end"}' input_file
上面的例子当第二列匹配到foo
时直接退出,END中的代码仍然会执行
IO statement
close(file)
关闭文件,管道
getline
- getline
将下一次输入赋值给$0
- getline var
将下一次输入赋值给var
String function
split(s, a [, r])
分割字符串s为数组a,r 是正则表达式,指定了分割符,a索引从1开始。
substr( s , i [ , n] )
返回字符串s从i开始的最多n个字符,i从1开始。
Function
可以定义自己的函数,在执行时调用,函数的语法是
function name ( parameter list ) { statements }
例子
假设有如下数据data.txt
ID,Name,Age,Score,Country
1,John Doe,28,85,USA
2,Jane Smith,32,90,UK
3,Franz Kafka,40,78,Germany
4,Diane Rios,25,95,USA
5,Akira Toriyama,65,88,Japan
6,Lee Min,22,90,South Korea
7,Patricia Luna,29,85,Mexico
8,Marco Rossi,52,73,Italy
9,Chen Wei,34,82,China
10,Ivan Ivanov,47,69,Russia
下面每个例子通过:awk -f read.awk data.txt
执行
打印每个国家的第一个出现的记录
# read.awk
BEGIN {
FS = ","
}
# seen 数组索引可以是字符串,数字...
NR > 1 && !seen[$5]++ {
print
}
END {
}
# 执行:awk -f read.awk file
按国家分组,计算每个国家人员的平均年龄
BEGIN {
FS = ","
}
NR > 1 {
totalAge[$5]+=$3
cnt[$5]++
}
END {
# country代表索引
for (country in totalAge) {
averageAge = totalAge[country] / cnt[country]
print country ", " averageAge
}
}
对所有记录按分数从高到低排序并输出
BEGIN {
FS = ",";
}
NR > 1 {
print $0 | "sort -t, -k4,4nr"; # 将记录传递给 sort 命令
}
END {
close("sort -t, -k4,4nr"); # 关闭 sort 命令的管道
}
为每个国家生成一个单独的文件,文件名格式为 Country.csv
,内容包含该国家的所有记录
BEGIN {
FS = ",";
head = ""
}
NR == 1 {
head = $0 # 保存标题行
}
NR > 1 {
country = $5
fname = country ".csv"
if (!seen[country]++) {
print head > fname # 对于每个国家的第一条记录,打印标题行
}
print $0 >> fname # 使用追加模式将记录添加到文件
}
END {
}