| · | 全称 | 描述 | example |
|---|---|---|---|
| NR | Number of Records | 当前记录行号, 从1开始, 全局累加,不管处理多少个文件 | awk '{ print NR, $0 }' file.txt 会在每行前打印行号。 |
| FNR | File Number of Records | 当前文件记录行号, 每个文件单独计数 | awk '{ print FNR, NR, $0 }' file1.txt file2.txt |
| NF | Number of Fields | 字段数 | awk '{ print NF, $NF }' file.txt NF 是字段数, $NF 是最后一个字段(非常常用) |
$1, $2, ... $NF可以直接用来访问行的各个字段。$0代表整行文本。
| · | 全称 | 描述 | example |
|---|---|---|---|
| OFS | Output Field Separator | 输出字段分隔符,默认是空格 | awk 'BEGIN { OFS=","; print "a", "b", "c" }' 会输出 a,b,c |
| ORS | Output Record Separator | 输出记录分隔符,默认是换行符 | awk 'BEGIN { ORS="---\n"; print "a"; print "b"; print "c" }' 会输出 a---\nb---nc---\n |
| FS | Field Separator | 输入字段分隔符,默认是空格 | awk -F, '{ print $1, $2 }' 会把逗号作为字段分隔符。 |
| RS | Record Separator | 输入记录分隔符,默认是换行符 | awk 'BEGIN { RS="---" } { print $0 }' 会把 --- 作为记录分隔符。 |
| · | 全称 | 描述 | example |
|---|---|---|---|
| FILENAME | - | 当前处理的文件名 | awk '{ print FILENAME, $0 }' file.txt 带上文件名打印每行。 |
| ARGC | - | 命令行参数个数 | awk 'BEGIN { print ARGC }' file.txt arg1 arg2 |
| ARGV | - | 命令行参数数组 | awk 'BEGIN { for (i=0; i<ARGC; i++) print ARGV[i] }' file.txt arg1 arg2 |
- awk 不认为自己在“处理文件”,而是在:处理一串有结构的记录.
- 默认:
- 记录(record)== 一行
- 字段(field) == 以 FS 分隔的列
record 1 -> $1 $2 $3 record 2 -> $1 $2 $3
- 所以 awk 的第一性原理是:
- 对每条记录执行同一段逻辑
- 这就是为什么, 不用写循环。
{ sum += $3 }
- awk 程序等价于:
while (getline) { if (pattern) action; }
- 设计哲学:程序员只描述“条件 + 动作”.
- awk 不是 if/for 为中心,而是:
pattern { action } - 甚至 pattern 可以省略:
{ print } - 这本质上是一个 规则系统(rule engine)。
- awk 的状态来源:
- 关联数组
- NR / NF / FNR
- 用户变量
- 哲学: 状态应当显式、扁平、可观察
- 这也是 awk 非常适合统计、聚合的原因。
- awk 的核心约束:
- 不缓存全文件
- 一次遍历
- 记录级处理
- 所以:
- 能用数组解决的就用数组
- 能一次算完的绝不回头
- FS / RS / OFS / ORS
BEGIN { FS=","; OFS="\t" }
- NR / FNR / NF
NR==1 { print "header" } NF<3 { next }
- 关联数组(awk 的灵魂)
count[$1]++ sum[$1] += $3 END { for (key in count) print key, count[key] }
- END / BEGIN
BEGIN { init } { process } END { report }
- 这是一个 Map → Reduce 的模型
用 SQL 思维写 awk
| SQL | awk |
|---|---|
| SELECT | {print} |
| WHERE | pattern |
| GROUP BY | array[key] |
| HAVING | END |
| ORDER BY | sort |
example
awk '{cnt[$2]++} END{for(k in cnt) if(cnt[k]>10) print k,cnt[k]}'$3 > 100 { print }不是:如果……然后……, 而是: 凡是满足条件的记录,都做这件事.
不要写:
for(i=1;i<=NF;i++) ...这是一条数据公式,不是脚本。
{ sum[$1]+=$3; cnt[$1]++ }
END { for(k in sum) print k, sum[k]/cnt[k] }Think of awk as just a simple program that iterates over your file one line at a time.
For every line in the file it checks to see whether that line has a certain pattern, if that line match a pattern, some action is performed.
NOTE: awk won't stop when if match a pattern, it will keep matching the rest patterns.
# PSEUDO
awk 'if(PATTERN1){ACTION1} if(PATTERN2){ACTION2} ...'Since this way of doing things is so common, the if statement is never written, and the brackets (), even the PATTERN, can be omitted.
# syntax
awk 'PATTERN1{ACTION1} PATTERN2{ACTION2} ...'- print the first 2 lines
NRstands forRow Number
$ ls -l | awk 'NR==1{print $0} NR==2{print}' total 0 drwx------@ 3 root staff 96 Dec 4 2021 Applications
- print full information of the first 3 lines, and only last field for the rest lines
NRstands forNumber of Fields
ls -l | awk 'NR<=3{print} NR>3{print $NF}' total 0 drwx------@ 3 root staff 96 Dec 4 2021 Applications drwx------@ 14 root staff 448 Jan 31 18:43 Desktop Documents Downloads Library Movies Music
- print the last 2nd filed
awk '....{print $(NF-1)}'
- awk treats space as the column delimiter
- use
-Fto specify a delimiter$awk -F ':' '{...}'
- The delimiter can be a regular expression.
$awk -F '[.:]' '{...}'
- print folder names which ends with
sls -l | awk '/s$/{print $NF}' Applications Documents Downloads Movies Pictures
- you can specify which field RE to be match
ls -l | awk '$0 ~ /s$/{print $NF}'
BEGIN/ENDare special pattern in awk. It doesn't match any specific line, but instead, cause the action to execute when awk starts up / shut down.
ls -l | awk '
BEGIN{temp_sum=0; total_records=0; print "Begin calculating average file size"}
NR>1{temp_sum += $5; total_records +=1;}
END{print "Average file size:" temp_sum/total_records }
'Begin calculating average file size
Average file size:506.273