命令格式
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
使用数据字段变量
$0
代表整个文本行$1
代表文本行中的第 1 个数据字段$2
代表文本行中的第 2 个数据字段$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版)》