Linux awk 速查手册

456 阅读5分钟

命令格式

awk 的基本格式为:awk options program file

-F fs 指定用于分隔行中数据字段的文件分隔符 
-f file 指定要读取的程序文件名 
-v var=value 定义 awk 程序中的一个变量及其默认值 
-mf N 指定要处理的数据文件中的最大字段数 
-mr N 指定数据文件中的最大记录数 
-W keyword 指定 awk 的兼容模式或警告等级,用 help 选项来列出所有可用的关键字

使用 awk

从命令行读取程序脚本

awk 程序脚本用一对花括号来定义

awk '{print "Hello World!"}' test.txt

使用数据字段变量

  1. $0 代表整个文本行
  2. $1 代表文本行中的第 1 个数据字段
  3. $2 代表文本行中的第 2 个数据字段
  4. $n 代表文本行中的第 n 个数据字段
cat data2.txt 
# One line of test text. 
# Two lines of test text. 
# Three lines of test text. 
awk '{print $1}' data2.txt 
# One 
# Two 
# Three

# -F 指定分隔符为 :
awk -F: '{print $1}' /etc/passwd 

在程序脚本中使用多个命令

要在命令行上的程序脚本中使用多条命令,只要在命令之间放个分号即可

# 给 $4 赋上新值 Christine
echo "My name is Rich" | gawk '{$4="Christine"; print $0}' 

从文件中读取程序

cat script2.gawk 
# {print $1 "'s home directory is " $6} 
awk -F: -f script2.gawk /etc/passwd 
# root's home directory is /root 
# bin's home directory is /bin 
# daemon's home directory is /sbin 
# [...] 

在处理数据前运行脚本

BEGIN 关键字会强制 awk 在读取数据前执行 BEGIN 关键字后指定的程序脚本

awk 'BEGIN {print "Hello World!"}' 

awk 'BEGIN {print "The data3 File Contents:"} {print $0}' data3.txt 
# The data3 File Contents: 
# Line 1 
# Line 2 
# Line 3

在处理数据后运行脚本

与 BEGIN 关键字类似,END 关键字允许指定一个程序脚本,awk 会在读完数据后执行它

awk 'BEGIN {print "The data3 File Contents:"} 
> {print $0} 
> END {print "End of File"}' data3.txt
# The data3 File Contents: 
# Line 1 
# Line 2 
# Line 3
# End of File

awk 变量

在 shell 中,引用变量需要加 $ 符,但在 awk 程序脚本里不需要 $ 符

内建变量

1.字段和记录分隔符变量

变量 描述
FIELDWIDTHS 由空格分隔的一列数字,定义了每个数据字段确切宽度
FS 输入字段分隔符
RS 输入记录分隔符
OFS 输出字段分隔符
ORS 输出记录分隔符
# 变量 FS 和 OFS 定义了 awk 如何处理数据流中的每行数据
cat data1 
# data11,data12,data13,data14,data15 
# data21,data22,data23,data24,data25 
# data31,data32,data33,data34,data3
awk 'BEGIN{FS=","; OFS="-"} {print $1,$2,$3}' data1 
# data11-data12-data13 
# data21-data22-data23 
# data31-data32-data33 

# FIELDWIDTHS 变量允许不依靠字段分隔符来读取记录,而是匹配数据在记录中的位置
# 一旦设置了 FIELDWIDTH 变量,awk 就会忽略 FS 变量,并根据提供的字段宽度来计算字段
cat data1b 
# 1005.3247596.37 
# 115-2.349194.00 
# 05810.1298100.1 
awk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1b 
# 100 5.324 75 96.37 
# 115 -2.34 91 94.00 
# 058 10.12 98 100.1 

# 变量 RS 和 ORS 定义了 awk 程序如何划分数据流中的行
cat data2 
# Riley Mullen 
# 123 Main Street Chicago, 
# IL  60601 (312)555-1234 
#  
# Frank Williams 
# 456 Oak Street Indianapolis, 
# IN  46201 (317)555-9876 
# 
# Haley Snell 
# 4231 Elm Street Detroit, 
# MI 48201 (313)555-4938 
# 将整个 data2 文件视作一行记录
awk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2 
# Riley Mullen (312)555-1234 
# Frank Williams (317)555-9876 
# Haley Snell (313)555-4938 $ 

2.数据变量

变量 描述
FNR 当前数据文件中的数据行数
IGNORECASE 设成非零值时,忽略 awk 命令中出现的字符串的字符大小写
NF 数据文件中的字段总数
NR 已处理的输入记录数
# FNR 变量含有当前数据文件中已处理过的记录数
# NR 变量则含有已处理过的记录总数
awk 'BEGIN{FS=","}{print $1,"FNR="FNR}' data1 data1 
# data11 FNR=1 
# data21 FNR=2 
# data31 FNR=3 
# data11 FNR=1 
# data21 FNR=2 
# data31 FNR=3
awk ' 
> BEGIN {FS=","} 
> {print $1,"FNR="FNR,"NR="NR} 
> END{print "There were",NR,"records processed"}' data1 data1 
# data11 FNR=1 NR=1 
# data21 FNR=2 NR=2 
# data31 FNR=3 NR=3 
# data11 FNR=1 NR=4 
# data21 FNR=2 NR=5 
# data31 FNR=3 NR=6 
# There were 6 records processed

自定义变量

1.在脚本中给变量赋值

cat data1
# data11,data12,data13
# data21,data22,data23
# data31,data32,data33

cat script1 
# BEGIN{FS=","} {print $n} 
# 相当于 awk 'BEGIN{FS=","} {print $2}' data1
awk -f script1 n=2 data1 
# data12 
# data22 
# data32

cat script2 
# BEGIN{print "The starting value is",n; FS=","} {print $n} 
# 如果要在 BEGIN 代码之前设定变量,需要加参数 -v,不然在 BEGIN 代码读取不了变量
awk -v n=3 -f script2 data1 

使用模式

正则表达式

在使用正则表达式时,正则表达式必须出现在它要控制的程序脚本的左花括号前

# 输出包含 11 的行
awk 'BEGIN{FS=","} /11/{print $1}' data1 

匹配操作符

匹配操作符(matching operator)允许将正则表达式限定在记录中的特定数据字段。匹配操作符是波浪线(~),可以指定匹配操作符、数据字段变量以及要匹配的正则表达式

# 过滤出第一个字段以文本data开头的所有记录
$1 ~ /^data/ 

# 第二个数据字段以文本 data2 开头的所有行
awk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1 

# 输出包含 rich 的行的第 1 个字段和最后 1 个字段
awk -F: '$1 ~ /rich/{print $1,$NF}' /etc/passwd 

# 用 ! 符号来排除正则表达式的匹配
# 输出不包含 rich 的行的第 1 个字段和最后 1 个字段
awk –F: '$1 !~ /rich/{print $1,$NF}' /etc/passwd 

数学表达式

表达式 描述
== 等于
<= 小于等于
< 小于
>= 大于等于
> 大于
# 显示所有属于 root 用户组(组 ID 为 0)的系统用户
awk -F: '$4 == 0{print $1}' /etc/passwd 

也可以对文本数据使用表达式,但必须小心。跟正则表达式不同,表达式必须完全匹配,数据必须跟模式严格匹配

# 无输出
awk -F, '$1 == "data"{print $1}' data1 

awk -F, '$1 == "data11"{print $1}' data1 
# data11 

结构化命令

if 语句

awk '{if ($1 > 20) print $1}' data.txt

awk '{if ($1 > 20) print $1 * 2; else print $1 / 2}' data.txt

while 语句

awk '{ 
> total = 0 
> i = 1 
> while (i < 4) 
> { 
>    total += $i 
>    if (i == 2) 
>       break 
>    i++ 
> } 
> avg = total / 2 
> print "The average of the first two data elements is:",avg 
> }' data.txt

do while 语句

awk '{ 
> total = 0 
> i = 1 
> do 
> { 
>    total += $i 
>    i++ 
> } while (total < 150) 
> print total }' data.txt

for 语句

awk '{ 
> total = 0 
> for (i = 1; i < 4; i++) 
> { 
>    total += $i 
> } 
> avg = total / 3 
> print "Average:",avg 
> }' data.txt

内建函数

1.数学函数

函数 描述
atan2(x, y) x/y 的反正切,x 和 y 以弧度为单位
cos(x) x 的余弦,x 以弧度为单位
exp(x) x 的指数函数
int(x) x 的整数部分,取靠近零一侧的值
log(x) x 的自然对数
rand() 比 0 大比 1 小的随机浮点值
sin(x) x 的正弦,x 以弧度为单位
sqrt(x) x 的平方根
and(v1, v2) 执行值 v1 和 v2 的按位与运算
compl(val) 执行 val 的补运算
lshift(val, count) 将值 val 左移 count 位
or(v1, v2) 执行值 v1 和 v2 的按位或运算
rshift(val, count) 将值 val 右移 count 位
xor(v1, v2) 执行值 v1 和 v2 的按位异或运算

2.字符串函数

函数 描述
asort(s [,d]) 将数组 s 按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。另外, 如果指定了 d,则排序后的数组会存储在数组 d 中
asorti(s [,d]) 将数组 s 按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表 明排序顺序。另外如果指定了 d,排序后的数组会存储在数组 d 中
gsub(r, s [,t]) 查找变量 $0 或目标字符串 t(如果提供了的话)来匹配正则表达式 r。如果找到了,就全部替换成字符串 s
index(s, t) 返回字符串 t 在字符串 s 中的索引值,如果没找到的话返回 0
length([s]) 返回字符串 s 的长度;如果没有指定的话,返回 $0 的长度
match(s, r [,a]) 返回字符串 s 中正则表达式 r 出现位置的索引。如果指定了数组 a,它会存储 s 中匹配正则表达式的那部分
split(s, a [,r]) 将 s 用 FS 字符或正则表达式 r(如果指定了的话)分开放到数组 a 中。返回字段的总数
sub(r, s [,t]) 在变量 $0 或目标字符串 t 中查找正则表达式 r 的匹配。如果找到了,就用字符串 s 替换掉第一处匹配
substr(s, i [,n]) 返回 s 中从索引值 i 开始的 n 个字符组成的子字符串。如果未提供 n,则返回 s 剩下的部分
tolower(s) 将 s 中的所有字符转换成小写
toupper(s) 将 s 中的所有字符转换成大写

3.时间函数

函数 描述
mktime(datespec) 将一个按 YYYY MM DD HH MM SS [DST] 格式指定的日期转换成时间戳值
strftime(format [,timestamp]) 将当前时间的时间戳或 timestamp(如果提供了的话)转化格式化日期(采用 shell 函数 date() 的格式)
systime() 返回当前时间的时间
awk 'BEGIN{ 
> date = systime() 
> day = strftime("%A, %B %d, %Y", date) 
> print day 
> }'
# Wednesday, April 08, 2020

4.自定义函数

awk ' 
> function myprint() 
> { 
>     printf "%-16s - %s\n", $1, $4 
> } 
> BEGIN{FS="\n"; RS=""} 
> { 
>     myprint() 
> }' data.txt


参考:《Linux命令行与Shell编程大全(第3版)》