AWK 备忘单
AWK 备忘单
这是 GNU awk 的 一页快速参考备忘单,其中涵盖了常用的 awk 表达式和命令。
开始
尝试一下
$ awk -F: '{print $1, $NF}' /etc/passwd
-F: | 冒号作为分隔符 |
{...} | awk 程序 |
print | 打印当前记录 |
$1 | 第一个字段 |
$NF | 最后一个字段 |
/etc/passwd | 输入数据文件 |
awk 程序
BEGIN {<initializations>}
<pattern 1> {<program actions>}
<pattern 2> {<program actions>}
...
END {< final actions >}
例子
awk '
BEGIN { print "\n>>>Start" }
!/(login|shutdown)/ { print NR, $0 }
END { print "<<<END\n" }
' /etc/passwd
变量
$1 $2/$(NF-1) $3/$NF
▼ ▼ ▼
┌──────┬──────────────┬───────┐
$0/NR ▶ │ ID │ WEBSITE │ URI │
├──────┼──────────────┼───────┤
$0/NR ▶ │ 1 │ quickref.me │ awk │
├──────┼──────────────┼───────┤
$0/NR ▶ │ 2 │ google.com │ 25 │
└──────┴──────────────┴───────┘
# First and last field
awk -F: '{print $1,$NF}' /etc/passwd
# With line number
awk -F: '{print NR, $0}' /etc/passwd
# Second last field
awk -F: '{print $(NF-1)}' /etc/passwd
# Custom string
awk -F: '{print $1 "=" $6}' /etc/passwd
请参阅:变量
awk 程序示例
awk 'BEGIN {print "hello world"}' # Prints "hello world"
awk -F: '{print $1}' /etc/passwd # -F: Specify field separator
# /pattern/ Execute actions only for matched pattern
awk -F: '/root/ {print $1}' /etc/passwd
# BEGIN block is executed once at the start
awk -F: 'BEGIN { print "uid"} { print $1 }' /etc/passwd
# END block is executed once at the end
awk -F: '{print $1} END { print "-done-"}' /etc/passwd
条件
awk '{if ($3>30) print $1}' /etc/passwd
见:条件
生成 1000 个空格
awk 'BEGIN{
while (a++ < 1000)
s=s " ";
print s
}'
请参阅:循环
数组
awk 'BEGIN {
fruits["mango"] = "yellow";
fruits["orange"] = "orange"
print fruits["orange"]
print fruits["mango"]
}'
请参阅:数组
函数
# => 5
awk 'BEGIN{print length("hello")}'
# => HELLO
awk 'BEGIN{print toupper("hello")}'
# => hel
awk 'BEGIN{print substr("hello", 1, 3)}'
请参阅:函数
awk 变量
内置变量
$0 | 全线 |
$1, $2...$NF | 第一个,第二个……最后一个字段 |
NR | 已经处理过的总记录数目,或者说行号(不一定是一个文件,可能是多个) |
NF | 一条记录的字段的数目 |
OFS | 当与输出上的 FS , 默认是以一个空格字符作为输出分隔符的 |
FS | 读取并解析输入文件中的每一行时,默认按照空格分隔为字段变量,$1,$2...等 |
ORS | 相当于输出的 RS 。 每条记录在输出时候会用分隔符隔开, |
RS | 定义了一行记录。读取文件时,默认将一行作为一条记录。 |
FILENAME | 文件名 |
表达式
$1 == "root" | 第一个字段等于根 |
{print $(NF-1)} | 倒数第二个字段 |
NR!=1{print $0} | 从第 2 个记录 |
NR > 3 | 从第 4 记录 |
NR == 1 | 第一条记录 |
END{print NR} | 总记录 |
BEGIN{print OFMT} | 输出格式 |
{print NR, $0} | 电话号码 |
{print NR " " $0} | 行号(选项卡) |
{$1 = NR; print} | 用行号替换第 1 个字段 |
$NF > 4 | 最后一个字段 > 4 |
NR % 2 == 0 | 连记录 |
NR==10, NR==20 | 记录 10 到 20 |
BEGIN{print ARGC} | 总参数 |
ORS=NR%5?",":"\n" | 连接记录 |
例子
打印总和和平均值
awk -F: '{sum += $3}
END { print sum, sum/NR }
' /etc/passwd
打印参数
awk 'BEGIN {
for (i = 1; i < ARGC; i++)
print ARGV[i] }' a b c
输出字段分隔符为逗号
awk 'BEGIN { FS=":";OFS=","}
{print $1,$2,$3,$4}' /etc/passwd
打印该字符串匹配Tw的起始位置
awk 'BEGIN {
if (match("One Two Three", "Tw"))
print RSTART }'
打印该字符串匹配re的字符串长度
awk 'BEGIN {
if (match("One Two Three", "re"))
print RLENGTH }'
环境变量
ARGC | 数字或参数 |
ARGV | 参数数组 |
FNR | F ILEN 的红棕色R ecords |
OFMT | 数字格式 (默认为“%.6g”) |
RSTART | 字符串中的位置 |
RLENGTH | 比赛时长 |
SUBSEP | 多维数组分隔符 (默认“\034”) |
ARGIND | 参数索引 |
仅限 GNU awk
ENVIRON | 环境变量 |
IGNORECASE | 忽略大小写 |
CONVFMT | 转换格式 |
ERRNO | 系统错误 |
FIELDWIDTHS | 固定宽度字段 |
定义变量
awk -v var1="Hello" -v var2="Wold" '
END {print var1, var2}
' </dev/null
使用 shell 变量
awk -v varName="$PWD" '
END {print varName}' </dev/null
awk 操作符
操作符
- | - |
---|---|
{print $1} | 第一个字段 |
$2 == "foo" | 等于 |
$2 != "foo" | 不等于 |
"foo" in array | 在数组中 |
正则表达式
- | - |
---|---|
/regex/ | 线路匹配 |
!/regex/ | 行不匹配 |
$1 ~ /regex/ | 字段匹配 |
$1 !~ /regex/ | 字段不匹配 |
更多条件
- | - |
---|---|
($2 <= 4 || $3 < 20) | 或者 |
($1 == 4 && $3 < 20) | 和 |
运算符
算术运算
- +
- -
- *
- /
- %
- ++
- --
速记作业
- +=
- -=
- *=
- /=
- %=
比较运算符
- ==
- !=
- <
- >
- <=
- >=
例子
awk 'BEGIN {
if ("foo" ~ "^fo+$")
print "Fooey!";
}'
不匹配
awk 'BEGIN {
if ("boo" !~ "^fo+$")
print "Boo!";
}'
如果在数组中
awk 'BEGIN {
assoc["foo"] = "bar";
assoc["bar"] = "baz";
if ("foo" in assoc)
print "Fooey!";
}'
awk 函数
常用功能
Function | Description |
---|---|
index(s,t) | 字符串 s 中出现字符串 t 的位置,如果未找到则为 0 |
length(s) | 字符串 s 的长度(如果没有 arg,则为 $0) |
rand | 0 到 1 之间的随机数 |
substr(s,index,len) | 返回从索引开始的 s 的 len-char 子串(从 1 开始计数) |
srand | 为 rand 设置种子并返回之前的种子 |
int(x) | 将 x 截断为整数值 |
split(s,a,fs) | 将字符串 s 拆分为由 fs 拆分的数组 a,返回 a 的长度 |
match(s,r) | 字符串 s 中出现正则表达式 r 的位置,如果未找到则为 0 |
sub(r,t,s) | 将 t 替换为字符串 s 中第一次出现的正则表达式 r(如果未给出 s,则为 $0) |
gsub(r,t,s) | 将 t 替换为字符串 s 中所有出现的正则表达式 r |
system(cmd) | 执行cmd并返回退出状态 |
tolower(s) | 字符串 s 转小写 |
toupper(s) | 字符串 s 为大写 |
getline | 将 $0 设置为当前输入文件的下一条输入记录。 |
用户定义函数
awk '
# Returns minimum number
function find_min(num1, num2){
if (num1 < num2)
return num1
return num2
}
# Returns maximum number
function find_max(num1, num2){
if (num1 > num2)
return num1
return num2
}
# Main function
function main(num1, num2){
result = find_min(num1, num2)
print "Minimum =", result
result = find_max(num1, num2)
print "Maximum =", result
}
# Script execution starts here
BEGIN {
main(10, 60)
}
'
awk 数组
带索引的数组
awk 'BEGIN {
arr[0] = "foo";
arr[1] = "bar";
print(arr[0]); # => foo
delete arr[0];
print(arr[0]); # => ""
}'
带键的数组
awk 'BEGIN {
assoc["foo"] = "bar";
assoc["bar"] = "baz";
print("baz" in assoc); # => 0
print("foo" in assoc); # => 1
}'
拆分数组
awk 'BEGIN {
split("foo:bar:baz", arr, ":");
for (key in arr)
print arr[key];
}'
带排序的数组
awk 'BEGIN {
arr[0] = 3
arr[1] = 2
arr[2] = 4
n = asort(arr)
for (i = 1; i <= n ; i++)
print(arr[i])
}'
多维数组
awk 'BEGIN {
multidim[0,0] = "foo";
multidim[0,1] = "bar";
multidim[1,0] = "baz";
multidim[1,1] = "boo";
}'
多维迭代
awk 'BEGIN {
array[1,2]=3;
array[2,3]=5;
for (comb in array) {
split(comb,sep,SUBSEP);
print sep[1], sep[2],
array[sep[1],sep[2]]
}
}'
awk 条件
if-else 语句
awk -v count=2 'BEGIN {
if (count == 1)
print "Yes";
else
print "Huh?";
}'
三元运算符
awk -v count=2 'BEGIN {
print (count==1) ? "Yes" : "Huh?";
}'
存在
awk 'BEGIN {
assoc["foo"] = "bar";
assoc["bar"] = "baz";
if ("foo" in assoc)
print "Fooey!";
}'
不存在
awk 'BEGIN {
assoc["foo"] = "bar";
assoc["bar"] = "baz";
if ("Huh" in assoc == 0 )
print "Huh!";
}'
switch 语句
awk -F: '{
switch (NR * 2 + 1) {
case 3:
case "11":
print NR - 1
break
case /2[[:digit:]]+/:
print NR
default:
print NR + 1
case -1:
print NR * -1
}
}' /etc/passwd
Awk 循环
for...i
awk 'BEGIN {
for (i = 0; i < 10; i++)
print "i=" i;
}'
1 到 100 之间的 2 次幂
awk 'BEGIN {
for (i = 1; i <= 100; i *= 2)
print i
}'
for...in
awk 'BEGIN {
assoc["key1"] = "val1"
assoc["key2"] = "val2"
for (key in assoc)
print assoc[key];
}'
参数
awk 'BEGIN {
for (argnum in ARGV)
print ARGV[argnum];
}' a b c
例子
反向记录
awk -F: '{ x[NR] = $0 }
END {
for (i = NR; i > 0; i--)
print x[i]
}
' /etc/passwd
反向字段
awk -F: '{
for (i = NF; i > 0; i--)
printf("%s ",$i);
print ""
}' /etc/passwd
按记录求和
awk -F: '{
s=0;
for (i = 1; i <= NF; i++)
s += $i;
print s
}' /etc/passwd
总和整个文件
awk -F: '
{for (i = 1; i <= NF; i++)
s += $i;
};
END{print s}
' /etc/passwd
while 语句
awk 'BEGIN {
while (a < 10) {
print "- " " concatenation: " a
a++;
}
}'
do...while 语句
awk '{
i = 1
do {
print $0
i++
} while (i <= 5)
}' /etc/passwd
break
awk 'BEGIN {
break_num = 5
for (i = 0; i < 10; i++) {
print i
if (i == break_num)
break
}
}'
continue
awk 'BEGIN {
for (x = 0; x <= 10; x++) {
if (x == 5 || x == 6)
continue
printf "%d ", x
}
print ""
}'
Awk 格式化打印
用法
右对齐
awk 'BEGIN{printf "|%10s|\n", "hello"}'
| hello|
左对齐
awk 'BEGIN{printf "|%-10s|\n", "hello"}'
|hello |
常用说明符
Character | Description |
---|---|
c | ASCII 字符 |
d | 十进制整数 |
e , E ,f | 浮点格式 |
o | 无符号八进制值 |
s | 细绳 |
% | 文字百分比 |
空间
awk -F: '{
printf "%-10s %s\n", $1, $(NF-1)
}' /etc/passwd | head -n 3
输出
root /root
bin /bin
daemon /sbin
标题
awk -F: 'BEGIN {
printf "%-10s %s\n", "User", "Home"
printf "%-10s %s\n", "----","----"}
{ printf "%-10s %s\n", $1, $(NF-1) }
' /etc/passwd | head -n 5
输出
User Home
---- ----
root /root
bin /bin
daemon /sbin
其他
正则表达式元字符
- \
- ^
- $
- .
- [
- ]
- |
- (
- )
- *
- +
- ?
转义序列
\b | 退格 |
\f | 换页 |
\n | 换行(换行) |
\r | 回车 |
\t | 水平标签 |
\v | 垂直标签 |
运行脚本
$ cat demo.awk
#!/usr/bin/awk -f
BEGIN { x = 23 }
{ x += 2 }
END { print x }
$ awk -f demo.awk /etc/passwd
69
另见
- GNU Awk 用户指南 (www-zeuthen.desy.de)
- AWK 备忘单 (gist.github.com)