25、AWK 杂项函数

这里的翻译有些错误,有些是内置的函数,有些是语句,也就是关键字。我统统将它们翻译成函数了...

捂脸~~~~~~~~~~~

关闭管道 close(expr)

函数close(cmd, [read_or_write]) 用于关闭已经打开的管道。

参数说明

参数 说明
cmd 要关闭的管道
read_or_write 要关闭的管道方向,如果不传则默认关闭管道,如果为 to 则关闭输入管道

范例

下面的范例演示了如何使用 close 关闭一个已经打开的管道

[www.ddkk.com]$ awk 'BEGIN {
   cmd = "tr [a-z] [A-Z]"
   print "hello, world !!!" |& cmd

   close(cmd, "to")
   cmd |& getline out
   print out;

   close(cmd);
}'

运行以上 awk 命令,输出结果如下

HELLO, WORLD !!!

上面这段程序看起来是不是很迷茫 ??

这估计是我们见过的最为复杂的程序了,下面我们就一步一步来拆解吧!!!

1、 第一行cmd="tr[a-z][A-Z]定义了一个系统命令,我们会使用这个命令开启一个双向通讯管道
2、 第二行print"hello,world!!!"|&cmd;

我们先来看 |& cmd ,这句话的意思是使用 |& 输出重定向运算符打开一个 双向通讯管道 连接当前 AWK 程序和刚刚定义的命令。

然后 print "hello, world !!!" |& cmd 就是把 print 函数的输出结果重定向到刚刚定义的 双向通讯管道

说的直白一点,就是 print 函数为 tr 命令提供了输入。 3、 第三行close(cmd,"to")用于关闭刚刚打开的双向通讯管道的输入进程;
4、 第四行cmd|&getlineout把tr命令的执行结果使用管道运算符&|重定向到getline函数getline函数会把结果储存到out变量中;
5、 最后一行close(cmd)用于关闭刚刚打开的双向通讯管道

删除数组元素 delete(arr)

AWK中数组的那些默认操作,就是只管添加不管删。如果要删除数组中的某个元素,需要用到 delete 函数。

它的原型如下

delete arr[i]

参数

参数 说明
arr[i] 要删除的数组的元素

范例

下面的awk 程序,演示了如何使用 delete 函数删除数组元素。

[www.ddkk.com]$ awk 'BEGIN {
   arr[0] = "One"
   arr[1] = "Two"
   arr[2] = "Three"
   arr[3] = "Four"
   print "Array elements before delete operation:"

   for (i in arr) {
      print arr[i]
   }
   delete arr[0]
   delete arr[1]
   print "Array elements after delete operation:"

   for (i in arr) {
      print arr[i]
   }
}'

运行以上 awk 命令,输出结果如下

Array elements before delete operation:
One
Two
Three
Four

Array elements after delete operation:
Three
Four

退出程序 exit([expr])

函数exit() 用于停止执行脚本。它之后的脚本就不再会执行了。

它的原型如下

exit [expr] 

参数expr 是可选的,它会成为 AWK 的返回值。

参数

参数 说明
expr 用于指定的 AWK 的返回值

范例

下面的程序,使用 exit 退出当前程序

[www.ddkk.com]$ awk 'BEGIN {
   print "DDKK.COM 弟弟快看,程序员编程资料站欢迎您"
   exit 10
   print "这句永远不会被执行啦....."
}'

DDKK.COM 弟弟快看,程序员编程资料站欢迎您

刷新缓冲区 fflush([output-expr])

几乎所有的语言中,都或多或少存在 flush() 这个函数,也存在 刷新缓冲区 这个概念。

刷新缓冲区 是什么意思呢 ? 哈哈,很简单的,就是把 储存在内存中的数据保存到文件或者管道中

一副,数据我给你保存了,断电了就不再关我啥事的~~~

函数fflush() 用于刷新与打开的输出文件或管道关联的任何缓冲区

它的函数原型如下

fflush([output-expr])

参数说明

参数 说明
output-expr 要刷新的缓冲区

1、 如果没有传递output-expr,那么默认刷新标准输出
2、 如果传递的是空字符串'',那么会刷新所有当前awk程序打开的文件或者管道;
3、 否则,刷新指定的文件或管道;

范例

范例,等等我找找...

读取下一行 getline

经过前面的渲染,我们知道,AWK 是一个行文本处理器。AWK 会把输入的每一个行都经过 模式/处理程序

如果我们要提前读取下一行,要怎么做呢?虽然我也不知道为啥会有这种需求,但,确实有这种需求啊。

不过还真别说,AWK 还真有个函数可以实现这种变态的需求,那就是 getline

函数getline 怎么说呢,简单的说,它用于读取下一行,复杂的说

1、 它会读取下一行,并进行分割并替代当前的 $ 0, $ 1最直接的影响,就是输入缓存也会被迭代到下一行;
2、 如果下一行不存在,也就是已经达到文件末尾,则什么都不做,也不会替换当前的 $ 0 $ 1...;

哎呀,有点说不清楚,直接看范例吧

它的函数原型如下

getline()

它既没有参数,也没有返回值,因此调用的时候可以直接输入 next 不用后面加括号。

范例

假设当前电脑上有个文件 employee.txt,内容如下

employee.txt

1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

下面的程序,使用 getline 读取下一行。

[www.ddkk.com]$ awk '{getline; print $0}' employee.txt

运行以上 awk 命令,输出结果如下

2)  李四  人力部  22
4)  赵六  技术部  24
5)  朱七  客服部  23

是不是对输出结果有点难以理解?为啥第一行、第三行消失了。。。。。

我们来分析下程序

1、 当程序开始执行第一行的时候,遇到getline,这时候不得不从输入缓存里读取下一行,也就是第二行,导致第一行的 $ 0, $ 1...被第二行代替,因此print $ 直接输出了第二行;
2、 print $ 0执行完之后,开始进入下一个迭代,这时候因为第二行已经读取了,处于缓存头部的是第三行,然后又因为getline语句,导致了第四行的输出;
3、 当开始第三个循环的时候,已经读取到第五行,这时候,当前的 $ 0等等也就是第五行的数据然后调用getline,因为已经到了文件末尾,getline没有读取到数据,那就不会执行替换, $ 0, $ 1...还是之前那个,也就是第五行数据;

处理下一行 next()

经过前面的渲染,我们知道,AWK 是一个行文本处理器。AWK 会把输入的每一个行都经过 模式/处理程序

那,如果我们不想处理当前行了,想直接进行下一行要怎么办呢?

因为不在 循环语句 中,所以 break 关键字失效啦。

为了应对这种情况,AWK 内置了 next() 函数用于处理下一行。

它的函数原型如下

next()

它既没有参数,也没有返回值,因此调用的时候可以直接输入 next 不用后面加括号。

范例

假设当前电脑上有个文件 employee.txt,内容如下

employee.txt

1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

下面的AWK 命令,当处理到 王五 的时候直接略过,继续处理下一行

[www.ddkk.com]$ awk '{if ($2 ~/王五/) next; print $0}' employee.txt

运行以上 awk 命令,输出结果如下

1)  张三  技术部  23
2)  李四  人力部  22
4)  赵六  技术部  24
5)  朱七  客服部  23

处理下一个文件 nextfile

AWK是可以处理多个文件的。那么当我们不想处理当前文件,想直接处理下一个文件了要怎么办呢 ?

答案就是: 使用 nextfile() 函数

函数 nextfile() 用于跳过当前文件的处理,直接进入下一个文件处理。

nextfile() 函数会改变程序的执行流程。确切的说,是 停止处理当前的输入文件,直接处理下一个文件,从下一个文件的第一行开始重新循环执行 模式/处理程序

函数 nextfile() 的原型为

nextfile()

它既没有参数,也没有返回值,因此调用的时候可以直接输入 nextfile 不用后面加括号。

范例

假设当前电脑上有两个文件,employee.txt 和 employee1.txt ,两个文件的内容如下

employee.txt

1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

employee1.txt

6)  小红  技术部  28
7)  小李  人力部  29
8)  小王  行政部  33
9)  小花  销售部  32
10)  小山  客服部  25

下面的AWK 命令,当处理到 王五 的时候直接跳过当前文件执行,继续执行下一个文件。

[www.ddkk.com]$ awk '{ if ($2 ~ /王五/) nextfile; print $0 }' employee.txt employee1.txt

运行以上 awk 命令,输出结果如下

1)  张三  技术部  23
2)  李四  人力部  22
6)  小红  技术部  28
7)  小李  人力部  29
8)  小王  行政部  33
9)  小花  销售部  32
10)  小山  客服部  25

函数返回值 return(expr)

AWK中的 return 竟然是一个函数,我去,而不是关键字~~~~~。

函数return(expr) 用于在用户自定义的函数中返回一个值。

它的原型如下

return(expr)

函数return(expr) 用于在用户自定义的函数中计算 expr 表达式的结果并将结果作为函数的返回值。

注意

与其它语言不同:

  1. AWK 中的 return 是函数而不是关键字
  2. 另一方面,如果没有传递 expr,那么 return 返回的结果是未定义的。

参数说明

参数 说明
expr 要返回的表达式

范例

我们首先在当前目录下创建一个文件 fns.awk 然后输入以下 AWK 命令

function msadd(num1, num2) {
   result = num1 + num2
   return result
}

BEGIN {
   res = msadd(15, 27)
   print "15 + 27 = " res
}

使用awk -f fns.awk 运行上面的 awk 命令,输出结果如下

15 + 27 = 42

执行系统脚本命令 system(command)

函数system(command) 用于执行系统脚本命令,并返回脚本执行的退出状态。

它的原型如下

system(command)

函数system(command) 用于执行系统脚本命令 command ,并返回脚本执行的退出状态。

退出状态分为以下几种:

1、 返回状态0表示命令执行成功;
2、 非零值表示命令执行失败;

参数说明

参数 说明
command 要执行的脚本命令

范例

以下示例显示当前日期,并显示该命令的返回状态

[www.ddkk.com]$ awk 'BEGIN { ret = system("date"); print "返回值为 = " ret }'

运行上面的 awk 命令,输出结果如下

2019年 05月 31日 星期五 23:39:29 CST
返回值为 = 0