目录
基本介绍
命令格式
awk基本使用
命令行读取程序脚本
数据字段变量
脚本中使用多个命令
文件中读取程序
处理数据前运行脚本(BEGIN)
处理数据后运行脚本(END)
awk高级用法
变量
内建变量
自定义变量
数组
定义数组变量
遍历数组变量
删除数组变量
使用模式
正则表达式
匹配操作符
数学表达式
结构化命令
if语句
while语句
do-while语句
for语句
内建函数
数学函数
字符串函数
时间函数
自定义函数
基本介绍
AWK是一种强大的文本处理工具,常用于在 Linux/Unix 系统中对文本文件进行模式扫描和处理。它非常适合处理结构化文本数据(如日志文件、CSV 文件等),并支持按行处理、字段提取、条件过滤和计算等操作。在awk编程语言中,你可以做下面的事情:
定义变量来保存数据; |
使用算术和字符串操作符来处理数据; |
使用结构化编程概念(比如 if-then 语句和循环)来为数据处理增加处理逻辑; |
通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。 |
命令格式
awk options program file
常用选项 | 描述 |
-F | 指定行中划分数据字段的字段分隔符 |
-f | 从指定的文件中读取程序 |
-v | 定义 awk 程序中的一个变量及其默认值 |
-mf | 指定要处理的数据文件中的最大字段数 |
-mr | 指定数据文件中的最大数据行数 |
awk基本使用
命令行读取程序脚本
[root@localhost ~]# awk '{print "Hello World!"}'
1
Hello World!
1
Hello World!
print命令会将文本打印到标准输出,若没有指定文本文件会从标准输入中接受数据。
数据字段变量
$0 | 代表整个文本行; |
$1 | 代表文本行中的第 1 个数据字段; |
$2 | 代表文本行中的第 2 个数据字段; |
$n | 代表文本行中的第 n 个数据字段。 |
以下为从data2.txt文件中获取每行的第一个字段和第二个字段。
[root@localhost ~]# cat data2.txt
One line of test text.
Two lines of test text.
Three lines of test text.[root@localhost ~]# awk '{print $1,$2}' data2.txt
One line
Two lines
Three lines
此外也可以用-F选项指定字段分割符
[root@localhost ~]# awk -F : '{print $1}' /etc/passwd | head -3
root
bin
daemon
脚本中使用多个命令
在脚本中运行多个命令,若在同一行中,只需在两条命令中加 ; 即可。
[root@localhost ~]# awk '{print "hello";print "world"}'hello
world
若在不同行中,则无需 ;。
[root@localhost ~]# awk '{
> print "hello"
> print "world"
> }'hello
world
文件中读取程序
awk使用 -f 参数从指定文件中读取程序
[root@localhost ~]# cat script2.awk
{print $1,"'s home is",$6
}[root@localhost ~]# awk -F : -f script2.awk /etc/passwd | head -3
root 's home is /root
bin 's home is /bin
daemon 's home is /sbin
处理数据前运行脚本(BEGIN)
[root@localhost ~]# cat data3.txt
Line 1
Line 2
Line 3
[root@localhost ~]# awk 'BEGIN {print "data3.txt:"}{print $0}' data3.txt
data3.txt:
Line 1
Line 2
Line 3
处理数据后运行脚本(END)
[root@localhost ~]# awk 'BEGIN {print "data3.txt:"}{print $0}END{print "end of file"}' data3.txt
data3.txt:
Line 1
Line 2
Line 3
end of file
awk高级用法
变量
- 内建变量
- 自定义变量
awk有一些自带的内建变量,用于存放处理数据文件中的数据字段和记录的信息等。
内建变量
- 字段和记录分隔符变量
变量 | 描述 |
FIELDWIDTHS | 由空格分隔的一列数字,定义了每个数据字段确切宽度 |
FS | 输入字段分隔符 |
RS | 输入记录分隔符 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
在BEGIN中用FS指定输入字段分割符,OFS指定输出字段分隔符,若不指定则都为空格。
[root@localhost ~]# cat data1.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35[root@localhost ~]# awk 'BEGIN{FS=","}{print $1,$2,$3}' data1.txt
data11 data12 data13
data21 data22 data23
data31 data32 data33[root@localhost ~]# awk 'BEGIN{FS=",";OFS="-"}{print $1,$2,$3}' data1.txt
data11-data12-data13
data21-data22-data23
data31-data32-data33
FIELDWIDTHS可以精确的指定每个字段的长度,这种方法不适用与变长的字段。
[root@localhost ~]# awk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1.txt
dat a11,d at a12,d
dat a21,d at a22,d
dat a31,d at a32,d
在awk中,可以根据情况指定RS输入记录分割符,以应对特殊情况。
[root@localhost ~]# cat data4.txt
Riley Mullen
123 Main Street
Chicago, IL 60601
(312)555-1234Frank Williams
456 Oak Street
Indianapolis, IN 46201
(317)555-9876Haley Snell
4231 Elm Street
Detroit, MI 48201
(313)555-4938[root@localhost ~]# awk 'BEGIN{FS="\n";RS=""}{print $1,$4}' data4.txt
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Haley Snell (313)555-4938
- 数据变量
变量 | 描述 |
ARGC | 当前命令行参数个数 |
ARGIND | 当前文件在 ARGV 中的位置 |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字的转换格式(参见 printf 语句),默认值为 %.6 g |
ENVIRON | 当前 shell 环境变量及其值组成的关联数组 |
ERRNO | 当读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | 用作 awk 输入数据的数据文件的文件名 |
FNR | 当前数据文件中的数据行数 |
IGNORECASE | 设成非零值时,忽略 awk 命令中出现的字符串的字符大小写 |
NF | 数据文件中的字段总数 |
NR | 已处理的输入记录数 |
OFMT | 数字的输出格式,默认值为 %.6 g |
RLENGTH | 由 match 函数所匹配的子字符串的长度 |
RSTART | 由 match 函数所匹配的子字符串的起始位置 |
自定义变量
[root@localhost ~]# awk 'BEGIN{testing="hello world"}{print testing}'hello world
自定义变量除了可以存字符串,也可以存数值,并进行数值运算
[root@localhost ~]# awk 'BEGIN{a=10
> a=a+15
> }
> {
> print a
> }'25
也可以在命令行上给变量赋值
[root@localhost ~]# cat data1.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35[root@localhost ~]# awk -F , '{print $n}' n=3 data1.txt
data13
data23
data33
但这种方法赋值的变量在BEGIN中不生效
[root@localhost ~]# awk -F , 'BEGIN{print n}{print $n}' n=3 data1.txt data13
data23
data33
也可以使用 -v 参数赋值变量,这样声明的变量在BEGIN中也能使用
[root@localhost ~]# awk -F , -v n=3 'BEGIN{print n}{print $n}' data1.txt
3
data13
data23
data33
数组
定义数组变量
[root@localhost ~]# cat script3.awk
BEGIN{str["name"] = "xiaoming"str["age"] = 18str["sex"] = "man"
}
{print str["name"]
}
[root@localhost ~]# awk -f script3.awk xiaoming
遍历数组变量
在awk中遍历数组,可以使用for in语句
for (var in array)
{
statements
}
这个for语句会在每次循环时将关联数组array的下一个索引值赋给变量var,然后执行一遍 statements。
[root@localhost ~]# cat script3.awk
BEGIN{str["name"] = "xiaoming"str["age"] = 18str["sex"] = "man"
}
{for(s in str){print s,":",str[s]}
}
[root@localhost ~]# awk -f script3.awk age : 18
sex : man
name : xiaoming
删除数组变量
delete array[index]
[root@localhost ~]# cat script3.awk
BEGIN{str["name"] = "xiaoming"str["age"] = 18str["sex"] = "man"
}
{delete str["age"]for(s in str){print s,":",str[s]}
}
[root@localhost ~]# awk -f script3.awk sex : man
name : xiaoming
使用模式
正则表达式
[root@localhost ~]# cat data5.txt
Alice 25 Engineer
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk '/^C/{print $0}' data5.txt
Charlie 22 Student
匹配操作符
[root@localhost ~]# cat data5.txt
Alice 25 Engineer
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk '$3 ~ /i/{print $0}' data5.txt
Alice 25 Engineer
Eve 28 Artist[root@localhost ~]# awk '$3 !~ /i/{print $0}' data5.txt
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
数学表达式
除了正则表达式,你也可以在匹配模式中用数学表达式。这个功能在匹配数据字段中的数字值时非常方便。
可以使用常见的数学比较表达式:
x == y | 值 x 等于 y |
x <= y | 值 x 小于等于 y |
x < y | 值 x 小于 y |
x >= y | 值 x 大于等于 y |
x > y | 值 x 大于 y |
[root@localhost ~]# cat data5.txt
Alice 25 Engineer
Bob 30 Doctor
Charlie 22 Student
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk '$2>=25{print $0}' data5.txt
Alice 25 Engineer
Bob 30 Doctor
David 35 Lawyer
Eve 28 Artist[root@localhost ~]# awk 'BEGIN{FS=":"}$1=="root"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash[root@localhost ~]# awk 'BEGIN{FS=":"}$1>="q"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
tss:x:59:59:Account used for TPM access:/:/usr/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
sssd:x:997:995:User for sssd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/usr/share/empty.sshd:/usr/sbin/nologin
redhat:x:1000:1000:redhat:/home/redhat:/bin/bash
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
结构化命令
if语句
[root@localhost ~]# cat data6.txt
10
5
13
50
34
[root@localhost ~]# awk '{if($1 > 20) print $1}' data6.txt
50
34
[root@localhost ~]# cat script4.awk
{if($1%400==0){print $1 " is Leap Year"}else if($1%4==0 && $1%100!=0)print $1 " is Leap Year"elseprint $1 " not is Leap Year"}
[root@localhost ~]# cat data7.txt
2014
2020
2017
2019
2024
2026
1900
[root@localhost ~]# awk -f script4.awk data7.txt
2014 not is Leap Year
2020 is Leap Year
2017 not is Leap Year
2019 not is Leap Year
2024 is Leap Year
2026 not is Leap Year
1900 not is Leap Year
while语句
[root@localhost ~]# cat data8.txt
130 120 135
160 113 140
145 170 215
[root@localhost ~]# cat script5.awk
BEGIN{sum=0
}
{s=0i=1while(i<NF){s+=$ii++}print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script5.awk data8.txt
1‘sum: 250
2‘sum: 273
3‘sum: 315
sum: 838
awk编程语言支持在while循环中使用break语句和continue语句,允许你从循环中跳出。
[root@localhost ~]# cat script5.awk
BEGIN{sum=0
}
{s=0i=1while(i<NF){s+=$ii++if(i==2)break}print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script5.awk data8.txt
1‘sum: 130
2‘sum: 160
3‘sum: 145
sum: 435
do-while语句
[root@localhost ~]# cat data8.txt
130 120 135
160 113 140
145 170 215
[root@localhost ~]# cat script6.awk
BEGIN{sum=0
}
{s=0i=1do{s+=$ii++}while(i<NF)print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script6.awk data8.txt
1‘sum: 250
2‘sum: 273
3‘sum: 315
sum: 838
for语句
[root@localhost ~]# cat data8.txt
130 120 135
160 113 140
145 170 215
[root@localhost ~]# cat script7.awk
BEGIN{sum=0
}
{s=0for(i=1;i<NF;i++){s+=$i}print NR "‘sum: " ssum+=s
}
END{print "sum: " sum
}
[root@localhost ~]# awk -f script7.awk data8.txt
1‘sum: 250
2‘sum: 273
3‘sum: 315
sum: 838
内建函数
数学函数
函数 | 描述 |
atan2(x, y) | x/y 的反正切, x 和 y 以弧度为单位 |
cos(x) | x 的余弦, x 以弧度为单位 |
exp(x) | x 的指数函数 |
int(x) | x 的整数部分,取靠近零一侧的值 |
log(x) | x 的自然对数 |
rand( ) | 比 0 大比 1 小的随机浮点值(不包括0或1) |
sin(x) | x 的正弦, x 以弧度为单位 |
sqrt(x) | x 的平方根 |
srand(x) | 为计算随机数指定一个种子值 |
字符串函数
函数 | 描述 |
asort(s [,d]) | 将数组 s 按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。另外, 如果指定了d ,则排序后的数组会存储在数组 d 中 |
asorti(s [,d]) | 将数组 s 按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表明排序顺序。另外如果指定了d ,排序后的数组会存储在数组d 中 |
gensub(r, s, h [, t]) | 查找变量 $0 或目标字符串 t (如果提供了的话)来匹配正则表达式r 。如果 h 是一个以 g或G 开头的字符串,就用 s 替换掉匹配的文本。如果 h 是一个数字,它表示要替换掉第h处r 匹配的地方 |
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 中。返回字段的总数 |
sprintf(format,variables) | 用提供的 format 和 variables 返回一个类似于 printf 输出的字符串 |
sub(r, s [,t]) | 在变量 $0 或目标字符串 t 中查找正则表达式 r 的匹配。如果找到了,就用字符串s 替换 掉第一处匹配 |
substr(s, i [,n]) | 返回 s 中从索引值 i 开始的 n 个字符组成的子字符串。如果未提供n ,则返回 s 剩下的部 分 |
tolower(s) | 将 s 中的所有字符转换成小写 |
toupper(s) | 将 s 中的所有字符转换成大写 |
[root@localhost ~]# awk '{print length($1)}'
hello
5
red
3[root@localhost ~]# cat script8.awk
BEGIN{a[0] = 45a[1] = 12a[2] = 34a[3] = 5asort(a)for(i in a){print a[i]}
}
[root@localhost ~]# awk -f script8.awk
5
12
34
45//split可以很方便的将字段放进数组中[root@localhost ~]# cat script9.awk
BEGIN{FS=":"
}
{split($0,var)print var[1],var[NF]
}
[root@localhost ~]# head -3 /etc/passwd | awk -f script9.awk
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
时间函数
函数 | 描述 |
mktime(datespec) | 将一个按 YYYY MM DD HH MM SS [DST] 格式指定的日期转换成时间戳值 |
strftime(format[,timestamp]) | 将当前时间的时间戳或 timestamp (如果提供了的话)转化格式化日期(采用shell函数date() 的格式) |
systime( ) | 返回当前时间的时间戳 |
下面是在awk程序中使用时间函数的例子。
[root@localhost ~]# cat script10.awk
{date=systime()print strftime("%Y %T",date)
}
[root@localhost ~]# awk -f script10.awk 2025 21:23:542025 21:23:562025 21:23:57
自定义函数
自定义函数基本格式
function name([variables])
{
statements
return value
}
在定义函数时,它必须出现在所有代码块之前(包括BEGIN代码块)。
[root@localhost ~]# cat script12.awk
function leap(year){if(year%400==0){print year " is Leap Year"}else if(year%4==0 && year%100!=0)print year " is Leap Year"elseprint year " not is Leap Year"}
BEGIN{for(i=2025;i<=2050;i++){leap(i)}
}[root@localhost ~]# awk -f script12.awk
2025 not is Leap Year
2026 not is Leap Year
2027 not is Leap Year
2028 is Leap Year
2029 not is Leap Year
2030 not is Leap Year
2031 not is Leap Year
2032 is Leap Year
2033 not is Leap Year
2034 not is Leap Year
2035 not is Leap Year
2036 is Leap Year
2037 not is Leap Year
2038 not is Leap Year
2039 not is Leap Year
2040 is Leap Year
2041 not is Leap Year
2042 not is Leap Year
2043 not is Leap Year
2044 is Leap Year
2045 not is Leap Year
2046 not is Leap Year
2047 not is Leap Year
2048 is Leap Year
2049 not is Leap Year
2050 not is Leap Year