回到:


getline用法详解

除了可以从标准输入或非选项型参数所指定的文件中读取数据,还可以使用getline从其它各种渠道获取需要处理的数据,它的用法有很多种。

getline的返回值:

  • 如果可以读取到数据,返回1
  • 如果遇到了EOF,返回0
  • 如果遇到了错误,返回负数。如-1表示文件无法打开,-2表示IO操作需要重试(retry)。在遇到错误的同时,还会设置ERRNO变量来描述错误

为了健壮性,getline时强烈建议进行判断。例如:

上面的getline的括号尽量加上,因为getline < 0表示的是输入重定向,而不是和数值0进行小于号的比较。

无参数的getline

getline无参数时,表示从当前正在处理的文件中立即读取下一条记录保存到$0中,并进行字段分割,然后继续执行后续代码逻辑

此时的getline会设置NF、RT、NR、FNR、$0和$N。

next也可以读取下一行。

  • getline:读取下一行之后,继续执行getline后面的代码

  • next:读取下一行,立即回头awk循环的头部,不会再执行next后面的代码

它们之间的区别用伪代码描述,类似于:

  1. # next
  2. exec 9<> filename
  3. while read -u 9 line;do
  4. ...code...
  5. continue # next
  6. ...code... # 这部分代码在本轮循环当中不再执行
  7. done
  8. # getline
  9. while read -u 9 line;do
  10. ...code...
  11. read -u 9 line # getline
  12. ...code...
  13. done

例如,匹配到某行之后,再读一行就退出:

  1. awk '/^1/{print;getline;print;exit}' a.txt

为了更健壮,应当对getline的返回值进行判断。

  1. awk '/^1/{print;if((getline)<=0){exit};print}' a.txt

一个参数的getline

没有参数的getline是读取下一条记录之后将记录保存到$0中,并对该记录进行字段的分割。

一个参数的getline是将读取的记录保存到指定的变量当中,并且不会对其进行分割。

  1. getline var

此时的getline只会设置RT、NR、FNR变量和指定的变量var。因此$0和$N以及NF保持不变。

  1. awk '
  2. /^1/{
  3. if((getline var)<=0){exit}
  4. print var
  5. print $0"--"$2
  6. }' a.txt

从指定文件中读取数据

filename需使用双引号包围表示文件名字符串,否则会当作变量解析getline < "c.txt"。此外,如果路径是使用变量构建的,则应该使用括号包围路径部分。例如getline < dir "/" filename中使用了两个变量构建路径,这会产生歧义,应当写成getline <(dir "/" filename)

注意,每次从filename读取之后都会做好位置偏移标记,下次再从该文件读取时将根据这个位置标记继续向后读取。

例如,每次行首以1开头时就读取c.txt文件的所有行。

  1. awk '
  2. /^1/{
  3. print;
  4. while((getline < "c.txt")>0){print};
  5. close("c.txt")
  6. }' a.txt

上面的close("c.txt")表示在while(getline)读取完文件之后关掉,以便后面再次读取,如果不关掉,则文件偏移指针将一直在文件结尾处,使得下次读取时直接遇到EOF。

从Shell命令输出结果中读取数据

  • cmd | getline:从Shell命令cmd的输出结果中读取一条记录保存到$0

    • 会进行字段划分,设置变量$0 NF $N RT,不会修改变量NR FNR
  • cmd | getline var:从Shell命令cmd的输出结果中读取数据保存到var中
    • 除了var和RT,其它变量都不会设置

如果要再次执行cmd并读取其输出数据,则需要close关闭该命令。例如close("seq 1 5"),参见下面的示例。

例如:每次遇到以1开头的行都输出seq命令产生的1 2 3 4 5

  1. awk '/^1/{print;while(("seq 1 5"|getline)>0){print};close("seq 1 5")}' a.txt

再例如,调用Shell的date命令生成时间,然后保存到awk变量cur_date中:

  1. awk '
  2. /^1/{
  3. print
  4. "date +\"%F %T\""|getline cur_date
  5. print cur_date
  6. close("date +\"%F %T\"")
  7. }' a.txt

可以将cmd保存成一个字符串变量。

  1. awk '
  2. BEGIN{get_date="date +\"%F %T\""}
  3. /^1/{
  4. print
  5. get_date | getline cur_date
  6. print cur_date
  7. close(get_date)
  8. }' a.txt

更为复杂一点的,cmd中可以包含Shell的其它特殊字符,例如管道、重定向符号等:

  1. awk '
  2. /^1/{
  3. print
  4. if(("seq 1 5 | xargs -i echo x{}y 2>/dev/null"|getline) > 0){
  5. print
  6. }
  7. close("seq 1 5 | xargs -i echo x{}y 2>/dev/null")
  8. }' a.txt

awk中的coprocess

awk虽然强大,但是有些数据仍然不方便处理,这时可将数据交给Shell命令去帮助处理,然后再从Shell命令的执行结果中取回处理后的数据继续awk处理。

awk通过|&符号来支持coproc。

  1. awk_print[f] "something" |& Shell_Cmd
  2. Shell_Cmd |& getline [var]

这表示awk通过print输出的数据将传递给Shell的命令Shell_Cmd去执行,然后awk再从Shell_Cmd的执行结果中取回Shell_Cmd产生的数据。

例如,不想使用awk的substr()来取子串,而是使用sed命令来替换。

  1. awk '
  2. BEGIN{
  3. CMD="sed -nr \"s/.*@(.*)$/\\1/p\"";
  4. }
  5. NR>1{
  6. print $5;
  7. print $5 |& CMD;
  8. close(CMD,"to");
  9. CMD |& getline email_domain;
  10. close(CMD);
  11. print email_domain;
  12. }' a.txt

对于awk_print |& cmd; cmd |& getline的使用,须注意的是:

  • awk_print |& cmd会直接将数据写进管道,cmd可以从中获取数据
  • 强烈建议在awk_print写完数据之后加上close(cmd,"to"),这样表示向管道中写入一个EOF标记,避免某些要求读完所有数据再执行的cmd命令被永久阻塞
  • 如果cmd是按块缓冲的,则getline可能会陷入阻塞。这时可将cmd部分改写成stdbuf -oL cmd以强制其按行缓冲输出数据
    • CMD="stdbuf -oL cmdline";awk_print |& CMD;close(CMD,"to");CMD |& getline

对于那些要求读完所有数据再执行的命令,例如sort命令,它们有可能需要等待数据已经完成后(遇到EOF标记)才开始执行任务,对于这些命令,可以多次向coprocess中写入数据,最后close(CMD,"to")让coprocess运行起来。

例如,对age字段(即$4)使用sort命令按数值大小进行排序:

  1. awk '
  2. BEGIN{
  3. CMD="sort -k4n";
  4. }
  5. # 将所有行都写进管道
  6. NR>1{
  7. print $0 |& CMD;
  8. }
  9. END{
  10. close(CMD,"to"); # 关闭管道通知sort开始排序
  11. while((CMD |& getline)>0){
  12. print;
  13. }
  14. close(CMD);
  15. } ' a.txt

close()

  1. close(filename)
  2. close(cmd,[from | to]) # to参数只用于coprocess的第一个阶段

如果close()关闭的对象不存在,awk不会报错,仅仅只是让其返回一个负数返回值。

close()有两个基本作用:

awk中任何文件都只会在第一次使用时打开,之后都不会再重新打开。只有关闭之后,再使用才会重新打开。

例如一个需求是只要在a.txt中匹配到1开头的行就输出另一个文件x.log的所有内容,那么在第一次输出x.log文件内容之后,文件偏移指针将在x.log文件的结尾处,如果不关闭该文件,则后续所有读取x.log的文件操作都从结尾处继续读取,但是显然总是得到EOF异常,所以getline返回值为0,而且也读取不到任何数据。所以,必须关闭它才能在下次匹配成功时再次从头读取该文件。

  1. awk '
  2. /^1/{
  3. print;
  4. while((getline var <"x.log")>0){
  5. print var
  6. }
  7. close("x.log")
  8. }' a.txt

在处理Coprocess的时候,close()可以指定第二个参数"from"或"to",它们都针对于coproc而言,from时表示关闭coproc |& getline的管道,使用to时,表示关闭print something |& coproc的管道。

  1. awk '
  2. BEGIN{
  3. CMD="sed -nr \"s/.*@(.*)$/\\1/p\"";
  4. }
  5. NR>1{
  6. print $5;
  7. print $5 |& CMD;
  8. close(CMD,"to"); # 本次close()是必须的
  9. CMD |& getline email_domain;
  10. close(CMD);
  11. print email_domain;
  12. }' a.txt

上面的第一个close是必须的,否则sed会一直阻塞。因为sed一直认为还有数据可读,只有关闭管道发送一个EOF,sed才会开始处理。

精通awk系列(12):awk getline用法详解的更多相关文章

  1. C#基础系列——多线程的常见用法详解

    前言:前面几节分别介绍了下C#基础技术中的反射.特性.泛型.序列化.扩展方法.Linq to Xml等,这篇跟着来介绍下C#的另一基础技术的使用.最近项目有点紧张,所以准备也不是特别充分.此篇就主要从 ...

  2. [js高手之路] es6系列教程 - promise常见用法详解(resolve,reject,catch,then,all,race)

    关于promise我在之前的文章已经应用过好几次,如[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist,本文就来讲解下pro ...

  3. 【OpenStack】OpenStack系列12之OpenStack自动化测试详解

    参考文档: https://github.com/yongluo2013/osf-openstack-training/blob/master/installation/How-to-setup-op ...

  4. Android GLSurfaceView用法详解(二)

    输入如何处理       若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件.下面有个例子: java代码: package eoe.ClearTes ...

  5. ZT --- extern "C"用法详解 2010-08-21 19:14:12

    extern "C"用法详解 2010-08-21 19:14:12 分类: C/C++ 1.前言: 时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus ...

  6. DAX/PowerBI系列 - 查询参数用法详解(Query Parameter)

    PowerBI  - 查询参数用法详解(Query Parameter) 很多人都不知道查询参数用来干啥,下面总结一下日常项目中常用的几个查询参数的地方.(本人不太欢hardcode的东西) 使用查询 ...

  7. (转)Shell中read的用法详解

    Shell中read的用法详解 原文:http://blog.csdn.net/jerry_1126/article/details/77406500 read的常用用法如下: read -[pstn ...

  8. golang格式化输出-fmt包用法详解

    golang格式化输出-fmt包用法详解 注意:我在这里给出golang查询关于包的使用的地址:https://godoc.org    声明: 此片文章并非原创,大多数内容都是来自:https:// ...

  9. (转)linux 中特殊符号用法详解

    linux 中特殊符号用法详解 原文:https://www.cnblogs.com/lidabo/p/4323979.html # 井号 (comments)#管理员  $普通用户 脚本中 #!/b ...

随机推荐

  1. 使用app测试Modelarts在线服务

    1. 基础准备 本demo代码已上传github地址为 https://github.com/zxzxzxygithub/hwmodelartdemo clone下来之后导入android studi ...

  2. 什么是API文档?--斯科特·马文

    有时候,软件开发人员想要的是自己的软件被其他应用软件所应用,而不是让人来操作.API使各种应用软件互相通信成为了可能. 从事API文档写作15年,我亲眼见证了API产品的崛起.各个公司开始搭建平台,希 ...

  3. 开发者如何学好 MongoDB

    作为一名研发,数据库是或多或少都会接触到的技术. MongoDB 是当前火热的 NoSQL 之一,我们怎样才能学好 MongoDB 呢?本篇文章,我们将从以下几方面讨论这个话题: MongoDB 是什 ...

  4. Pandas学习(二)——双色球开奖数据分析

    学习笔记汇总 Pandas学习(一)–数据的导入 pandas学习(二)–双色球数据分析 pandas学习(三)–NAB球员薪资分析 pandas学习(四)–数据的归一化 pandas学习(五)–pa ...

  5. bug小结

    在不同的文件下面可以创建同一个包,但是不能创建同一个class文件!!!   ParameterType:需要写实体类的类型,最好不要写实体的别名 这是因为我们在配置mybatis的配置文件时已经说明 ...

  6. hdu4585Shaolin

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4585 题意: 第一个人ID为1,战斗力为1e9. 给定n,给出n个人的ID和战斗力. 每个人必须和战斗 ...

  7. 2017 ACM/ICPC 沈阳 F题 Heron and his triangle

    A triangle is a Heron’s triangle if it satisfies that the side lengths of it are consecutive integer ...

  8. WebAPI测试概念及postman初识

    什么是接口?   ------   某个对象和外界交互的部分 消息交互接口:基于soap的web service  ---- http协议 web api   ------- http协议 diame ...

  9. 笔记||Python3之对象与变量

    什么是对象?什么是变量? 在python中,一切都是对象,一切都是对象的引用. 变量相当于数学中的等式,比如xy = 20 .在编程中变量还可以是任意数据类型. 对象是分配的一块内存,有足够的空间去表 ...

  10. 【玩转SpringBoot】用好条件相关注解,开启自动配置之门

    自动配置隐含两层含义,要搞清楚 上帝让程序员的发量减少,是为了让他变得更聪明,如果有一天聪明到了极点,那就是绝顶聪明. 据说在大脑高速运转下,这样更有利于散热,不至于核心温度过高而产生告警. 聪明的大 ...