awk文本处理工具和编程语言

功能说明: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

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注