功能说明:awk是一个强大的文本处理工具和编程语言,主要用于在 Unix 和 Linux 系统中对文本进行格式化、分析和处理。
语 法:awk -f ‘scripts’ -v var=value filename
awk ‘BEGIN{ print “start” } pattern{ commands } END{ print “end” }’ filename
补充说明:awk 可以逐行读取文件或者输入流(包括stdin),按照用户指定的模式和操作来处理文本数据,特别适用于结构化的文本(如表格、CSV、日志等结构化数据)。awk可在命令行中使用,但更多是作为脚本来使用。awk作为一门编程语言有很多内建的功能,比如数组、函数等,这是它和C语言的相似之处。
选 项:
-F 指定分隔符(可以是字符串或正则表达式)
-f ‘scripts’ 从脚本文件’scripts’中读取awk命令
-v var=value 赋值变量,将外部变量传递给awk
awk脚本基本结构:
pattern 用于匹配特定的行
{ commands } 用于对匹配的行执行操作
filename 要被awk处理的文件
一个awk脚本通常由BEGIN语句+模式匹配+END语句三部分组成,这三部分都是可选项。工作步骤:
第一步,执行BEGIN语句
第二步,从文件或标准输入读取一行,然后再执行pattern语句,以此类推,逐行扫描文件到文件全部被读取
第三步,执行END语句
awk内置变量:
awk默认将每行文本按照空格或特定分隔符分成多个字段(列),每个字段可以通过 $ 符号访问:
$0 当前记录(行)
$n 当前记录(行)的第n个字段(列),$1代表第1列,$n代表第n列
FS 字段(列)的分隔符(默认是空格或制表符),可以使用-F选项自定义分隔符
OFS 输出字段(列)分隔符(用于格式化输出)
RS 记录(行)的分隔符,默认是换行符
ORS 输出记录(行)的分隔符,默认是换行符
NR 当前处理的行号,默认从1开始
NF 当前行的字段(列)数
awk运算符:
算术运算符:
+ 加
– 减
* 乘
/ 除
% 求余
^ 求幂
++ 自增,作为前缀或后缀
— 自减,作为前缀或后缀
注意,非数值的变量在使用算术运算符时会被自动转换为0
赋值运算符:
=
+=
-=
*=
/=
%=
^=
正则运算符:
~ 匹配正则表达式
!~ 不匹配正则表达式
逻辑运算符:
|| 逻辑或
&& 逻辑与
关系运算符:
<
<=
>
>=
!=
==
其它运算符:
$ 通过序号引用字段(列)
空格 字符串链接符
?: 三目运算符
ln 数组中是否存在某键值
awk正则表达式语法:
^ 行首定位符
$ 行尾定位符
. 匹配任意单个字符
* 匹配0个或多个前导字符(包括回车)
+ 匹配1个或多个前导字符
? 匹配0个或1个前导字符
[] 匹配指定字符组内的任意一个字符/^[ab]
[^] 匹配不在指定字符组内的任意一个字符
() 子表达式
| 或
\ 转义符
~ 匹配条件语句
!~ 不匹配条件语句
x{m} x字符重复m次
x{m,} x字符至少重复m次
X{m,n} x字符至少重复m次但不起过n次(需指定选项-posix或–re-interval)
awk打印(输出)命令:
print简单输出,用于输出字段(列)或文本,自动在每个字段(列)间插入空格,并在行末自动换行
printf提供了更多格式控制,可以指定字段的输出格式、宽度、对齐方式等。它类似于 C 语言的 printf 函数。若要输出换行,需要手动添加换行符\n
awk读取输入命令:
getline用于读取文件或命令的输出
awk内置函数:
toupper函数将所有小写字母转换成大写字母
length函数返回字符个数
system函数可以用来调用系统命令,虽然它不直接打印到终端,但可以执行其他命令并返回执行结果
awk自定义函数:
awk脚本中可以定义自己的函数,例如
function square(x) {
return x * x
}
awk ‘{ print square($1) }’ file.txt
awk流程控制语句:
if-else 条件判断
while 和 do-while 循环
for 循环,包括 for-in 数组遍历
break 和 continue 控制循环的执行
exit 终止脚本执行
next 跳过当前行
return 函数返回值
三元条件表达式 ? :
awk数组:
awk 支持关联数组,这意味着数组的索引不仅可以是整数,也可以是字符串。awk 中的数组无需声明,也不需要定义大小,直接通过索引赋值即可使用。
实 例:
1 输入和输出
$ echo “hello ” | awk ‘BEGIN{ print “start” } END{ print “end” }’
start
end
打印读取到的文本:
$ echo “hello ” | awk ‘BEGIN{ print “start” } {print} END{ print “end” }’
start
hello
end
打印整行:
$ echo “Hello World” | awk ‘{print $0}’
Hello World
打印特定字段(列):
$ echo “Alice 30” | awk ‘{print $1}’ # 输出第一列,awk默认以空白符分隔列
Alice
打印多个字段:
$ echo “Alice 30” | awk ‘{print $1, $2}’
Alice 30
简单格式化输出
$ echo “Alice 30” | awk ‘{printf “%s is %d years old\n”, $1, $2}’
Alice is 30 years old
指定输出列的宽度:
$ echo “Alice 30” | awk ‘{printf “%-10s %-5d\n”, $1, $2}’ # %-10s 表示左对齐,宽度为10;%-5d 表示左对齐,宽度为5
Alice 30
控制小数点位数:
$ echo “3.14159” | awk ‘{printf “%.2f\n”, $1}’
3.14
输出到文件或追加到文件:
awk 的 print 和 printf 命令都可以配合 >, >> 操作符,将内容输出到文件中:
- 输出到文件:使用 > 将输出重定向到文件(会覆盖文件内容)。
- 追加到文件:使用 >> 将输出追加到文件(不会覆盖已有内容)。
将输出写入文件:
$ echo “Alice 30” | awk ‘{print $1, $2 > “output.txt”}’ # 结果输出到 output.txt 文件中
将输出追加到文件:
$ echo “Bob 25” | awk ‘{print $1, $2 >> “output.txt”}’ # 输出会追加到 output.txt 文件末尾
重定向输出到标准错误stderr:
$ echo “Error message” | awk ‘{print $0 > “/dev/stderr”}’
输出多列时自定义列的分隔符:
$ echo -e “Alice 30\nBob 25″ | awk ‘BEGIN { OFS=” | ” } {print $1, $2}’
Alice | 30
Bob | 25
使用 getline 读取文件或命令的输出:
$ awk ‘BEGIN { while ((getline line < “input.txt”) > 0) print line }’ # 从 input.txt 文件中逐行读取并输出内容
2 普通变量的定义和使用
定义多个变量,然后打印它们:
$ echo|awk ‘{ a=”aa”; b=”bb”; c=”cc”; print a,b,c; }’
aa bb cc
print语句中的””起到拼接字符串的作用:
$ echo|awk ‘{ a=”aa”; b=”bb”; c=”cc”; print a” is “b” or “c; }’
aa is bb or cc
3 内置变量的使用
打印文件中的第一列和第三列:
$ cat test.txt
aa bb cc dd ee
11 22 33 44 55
xyz yui tt
$ awk ‘{ print $1, $3 }’ test.txt
aa cc
11 33
xyz tt
$ awk ‘{ print $n }’ test.txt
aa bb cc dd ee
11 22 33 44 55
xyz yui tt
打印第二列第一列并以,符号分隔:
$ awk ‘{print $2″,”$1}’ test.txt
bb,aa
22,11
yui,xyz
打印每行的行号和字段(列)数:
$ awk ‘{ print NR, NF }’ test.txt
1 5
2 5
3 3
4 外部变量的使用
$ a=100
$ b=100
$ echo |awk ‘{print v1*v2 }’ v1=$a v2=$b
10000
$ e=eee
$ echo |awk ‘{print e }’ e=$e
eee
在shell中,awk可以直接使用shell的环境变量。
5 awk运算符的使用
$ awk ‘BEGIN{a=”b”;print a,a++,a–,++a;}’
b 0 1 1
$ awk ‘BEGIN{a=”0″;print a,a++,a–,++a;}’
0 0 1 1
$ awk ‘BEGIN{a=7;b=2;print a/b;}’
3.5
$ awk ‘BEGIN{a=7;b=2;print a%b;}’
1
$ awk ‘BEGIN{a=7;b=2;print a^b;}’
49
$ awk ‘BEGIN{a=7;b=2;print a==b;}’
0
$ awk ‘BEGIN{a=7;b=2;print a=b;}’
2
打印第二列是22的行第一列:
$ cat test.txt
aa bb cc dd ee
11 22 33 44 55
xyz yui tt
$ awk ‘($2 == 22) {print $1}’ test.txt
11
打印第3列的值大于66的行:
$ awk ‘$3 > 66’ test.txt
aa bb cc dd ee
xyz yui tt
? :三目运算符的使用示例:
$ awk ‘BEGIN{a=”b”;print a==”b”?”yes”:”no”}’
yes
6 正则表达式的使用
$ cat test.txt
aa bb cc dd ee
11 22 33 44 55
xyz yui tt
打印以a开头的行的第2列:
$ awk ‘/^a/{print $2}’ test.txt
bb
打印以a开头的行的第2列,并在第2列前加上aaa子串:
$ awk ‘/^a/{print “aaa”$2}’ test.txt
aaabb
打印第1列匹配xyz的行的第3列的值:
$ awk ‘$1~/xyz/ {print $3}’ test.txt
tt
如果变量a中包含test子串,那么打印yes:
$ echo|awk ‘BEGIN{a=”100testaaa”}a~/test/{print “yes”}’
yes
输出所有包含子串root的行:
awk ‘/root/{print $0}’ test.txt
7 awk内置函数的使用
toupper函数将所有小写字母转换成大写字母:
$ cat test.txt
aa bb cc dd ee
11 22 33 44 55
xyz yui tt
$ awk ‘{print toupper($0)}’ test.txt
AA BB CC DD EE
11 22 33 44 55
XYZ YUI TT
length函数返回字符个数。打印长度为3个字符的第一列的内容:
$ awk ‘{if(length($1) == 3) print $1}’ test.txt
xyz
8 处理不同分隔符的文件
通过设置 -F 选项来指定输入的字段的分隔符。例如,对于以逗号分隔的 CSV 文件:
$ cat test.csv
ttc,yui,layui,tailwind
c,c++,go,java,python,php,js
apple,google,facebook,reddit,twitter,amazon
john@Ubuntu22-VirtualBox:~/test$ awk -F ‘,’ ‘{ print $1, $2 }’ test.csv
ttc yui
c c++
apple google
如果不使用-F ‘,’选项,就无法正确处理CSV文件:
$ awk ‘{ print $1, $2 }’ test.csv
ttc,yui,layui,tailwind
c,c++,go,java,python,php,js
apple,google,facebook,reddit,twitter,amazon
9 awk脚本的编写和使用
除了命令行上使用,我们也可以编写awk脚本文件,适合复杂的数据处理任务。例如,保存以下代码到 script.awk 文件中:
BEGIN { FS=”,”; OFS=” – ” }
{ print $1, $3 }
然后用 awk -f script.awk test.csv 来执行这个脚本:
$ awk -f script.awk test.csv
ttc – layui
c – go
apple – facebook
10 控制流程的使用
10.1 if-else 语句(条件判断)
$ cat test.txt
aa bb cc dd ee
11 22 33 44 55
xyz yui tt
$ awk ‘{ if ($3 > 66) print $1, $3; else print $3, “not greater” }’ test.txt
aa cc
33 not greater
xyz tt
可以嵌套多个 if-else 语句:
awk ‘{ if ($1 > 10) print “Greater”; else if ($1 == 10) print “Equal”; else print “Smaller” }’ file.txt
10.2 while 语句(循环)
awk ‘{ i = 1; while (i <= NF) { print $i; i++ } }’ file.txt
10.3 do-while 语句(后测试循环)
do-while 循环会先执行一次循环体,然后检查条件是否为真:
awk ‘{ i = 1; do { print $i; i++ } while (i <= NF) }’ file.txt
10.4 for 语句(循环)
awk ‘{ for (i = 1; i <= NF; i++) print $i }’ file.txt
10.5 for-in遍历数组的所有索引
awk ‘{ for (i in arr) print arr[i] }’
10.6 break 语句(跳出循环)
awk ‘{ for (i = 1; i <= NF; i++) { if ($i == “stop”) break; print $i } }’ file.txt
10.7 continue 语句(继续下一次循环)
continue 语句用于跳过本次循环的剩余部分,并继续执行下一次循环:
awk ‘{ for (i = 1; i <= NF; i++) { if ($i == “skip”) continue; print $i } }’ file.txt
10.8 exit 语句(退出程序)
exit 语句用于终止 awk 脚本的执行,退出脚本时可以指定退出状态码:
awk ‘{ if ($1 == “exit”) exit; print $1 }’ file.txt
立即终止脚本的执行,剩余的行不会被处理。
可以在 END 块中使用 exit 返回状态码:
awk ‘END { if (NR == 0) exit 1 }’ file.txt
10.9 next 语句(跳到下一行)
next 语句用于跳过当前行的剩余操作,直接处理下一行:
awk ‘{ if ($1 == “skip”) next; print $1 }’ file.txt
10.10 return 语句(函数中使用)
return 语句用于在函数中返回值并退出函数:
function square(x) {
return x * x
}
awk ‘{ print square($1) }’ file.txt
10.11 条件表达式(三元操作符)
awk ‘{ print ($1 > 10 ? “Greater” : “Smaller”) }’ file.txt
11 数组
11.1 定义和使用数组
awk 中通过赋值操作可以直接定义数组。例如:
awk ‘BEGIN { arr[1] = “apple”; arr[2] = “banana”; print arr[1], arr[2] }’
在这个例子中,arr[1] 和 arr[2] 定义了两个元素,分别存储 “apple” 和 “banana”。
使用字符串作为数组的索引:
awk ‘BEGIN { arr[“fruit”] = “apple”; print arr[“fruit”] }’
11.2 遍历数组
你可以使用 for-in 循环遍历数组中的所有元素,数组中的索引会被 for 循环访问:
awk ‘BEGIN {
arr[1] = “apple”;
arr[2] = “banana”;
arr[3] = “cherry”;
for (i in arr) {
print i, arr[i];
}
}’
这个例子会遍历数组 arr,输出数组的索引和对应的值。值得注意的是,awk 中 for-in 循环的遍历顺序并不保证是按索引的顺序,具体顺序取决于 awk 的实现。
11.3 删除数组元素
可以使用 delete 语句删除数组中的某个元素:
awk ‘BEGIN {
arr[1] = “apple”;
arr[2] = “banana”;
delete arr[1];
print arr[1]; # 输出为空,因为arr[1]已被删除
}’
delete 会将指定的数组元素完全移除,后续对该索引的访问将返回空值。
11.4 计算数组长度
awk 本身没有直接的函数来计算数组的长度,但你可以通过遍历数组来计算元素个数。例如:
awk ‘BEGIN {
arr[1] = “apple”;
arr[2] = “banana”;
arr[3] = “cherry”;
count = 0;
for (i in arr) {
count++;
}
print “Array length:”, count;
}’
11.5 多维数组
虽然 awk 本质上是支持一维数组,但可以通过组合索引来实现多维数组的效果。你可以使用多个索引作为键,例如:
awk ‘BEGIN {
arr[1,1] = “apple”;
arr[1,2] = “banana”;
arr[2,1] = “cherry”;
print arr[1,1]; # 输出apple
print arr[1,2]; # 输出banana
print arr[2,1]; # 输出cherry
}’
这里 arr[1,1] 和 arr[1,2] 类似于二维数组的定义,逗号 , 将多个索引组合在一起。
11.6 数组的默认值
在 awk 中,未被初始化的数组元素会默认返回空字符串或 0,具体取决于如何使用。例如:
awk ‘BEGIN {
print arr[1]; # 输出为空,因为arr[1]未被初始化
}’
如果试图对一个未初始化的数组元素进行运算操作,它将被视为 0。
12 综合实例
获取enp0s3网卡的IP地址:
$ ifconfig enp0s3|awk ‘BEGIN{FS=”[[:space:]:]+”} NR==2{print $3}’
10.0.2.15
打印当前目录下的子目录和文件的总字节数,以MB为单位:
$ ls -alh|awk ‘BEGIN{size=0;} {size=size+$5;} END{print “total size is “,size/1024/1024,”MB”}’
total size is 0.000601768 MB