欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

awk入门(三)--getline用法 有大用



本文示例文本

~]$ cat a.txt
ID  name    gender  age  email          phone
1   Bob     male    28   abc@qq.com     18023394012
2   Alice   female  24   def@gmail.com  18084925203
3   Tony    male    21   aaa@163.com    17048792503
4   Kevin   male    21   bbb@189.com    17023929033
5   Alex    male    18   ccc@xyz.com    18185904230
6   Andy    female  22   ddd@139.com    18923902352
7   Jerry   female  25   exdsa@189.com  18785234906
8   Peter   male    20   bax@qq.com     17729348758
9   Steven  female  23   bc@sohu.com    15947893212
10  Bruce   female  27   bcbd@139.com   13942943905
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

作用:getline主要用于读取需要被处理的内容
工作方式:读取下一行之后,继续执行getline后面的代码
数据源:getline可以从标准输入,非选项型文件,另外还可以通过重定向的方式获取数据
返回值:getline在读取数据时,会自动返回一个整数值,包括0,正负数

  • 如果getline可以获取到数据,则返回1(比如读取一个非空文件)

  • 如果遇到EOF,则返回0(文件读取到最后一行,或者从标准输入收到EOF

  • 如果遇到错误,则会返回负值(-1表示文件无法打开,-2表示需要重试,同时还会用变量来描述错误)

对输入内容的判断

由于getline读取数据源时可能会出现问题,因此需要对getline的数据源进行判断,从而便于排错:

if((getline < "filename") >0){...} ##文件名需要用双引号包围,否则报错
if((getline) <= 0){...}
if((getline) < 0 ){...}
  • 1

  • 2

  • 3

getline数据处理顺序问题

getline是读取当前行的下一行,然后交给后续代码处理:
getline是处于awk的main代码块中,如果放在BEGIN或END代码块中则不能发挥其功能

1.放在main代码块中
~]$ awk '{if((getline) > 0 ){print $0}}' a.txt  ##这样的话就能读取偶数行
读取奇数行:
~]$ awk 'NR>=2{if((getline) > 0){print $0}}' a.txt

2.放在BEGIN代码块
~]$ awk 'BEGIN{while((getline) > 0){print $0}}' a.txt  ##这样能全部读取
3.放在END代码块
因为END代码块是在文件处理完成之后才执行,因此此时getline已没有数据源了,因此这时getline是不生效的
`注意:getline放在main代码段和BEGIN代码段中的输出是有区别的
~]$ awk 'BEGIN{while((getline) > 0){print $0}}' a.txt ##输出全文,因为在BEGIN代码块中读取了一条记录才会进入main代码块
~]$ awk '{while((getline) > 0){print $0}}' a.txt  #第一行会被getline跳过
`
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

无参数的getline

getline无参数时,表示读取下一条记录并保存到$0中,并且会继续执行后续的代码逻辑,并且进行字段分割,然后继续执行后续的代码逻辑 此时的getline会设置NR,FNR,$0和$N

~]$ cat test.txt
1-2-3-4-5
2-3-4-5-6
3-4-5-6-1
4-5-6-1-2
5-6-1-2-3
6-1-2-3-4
~]$ awk -F '-' '{while((getline) > 0 ){print $1}}' test.txt ##默认会跳过第一行
2
3
4
5
6

~]$ awk -F '-' 'BEGIN{while((getline) > 0 ){print NF}}' test.txt
5
5
5
5
5
5

~]$ awk -F '-' 'BEGIN{while((getline) > 0 ){print NR}}' test.txt
1
2
3
4
5
6

~]$ awk -F '-' 'BEGIN{while((getline) > 0 ){print FNR}}' test.txt
1
2
3
4
5
6
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

一个参数的getline

一个参数的getline在读取记录时,会将下一条记录放在变量中,并且不会对其分割

~]$  awk '{if((getline var1) <= 0){exit}{print var1}{print $0}}' a.txt
1   Bob     male    28   abc@qq.com     18023394012
ID  name    gender  age  email          phone
3   Tony    male    21   aaa@163.com    17048792503
2   Alice   female  24   def@gmail.com  18084925203
5   Alex    male    18   ccc@xyz.com    18185904230
4   Kevin   male    21   bbb@189.com    17023929033
7   Jerry   female  25   exdsa@189.com  18785234906
6   Andy    female  22   ddd@139.com    18923902352
9   Steven  female  23   bc@sohu.com    15947893212
8   Peter   male    20   bax@qq.com     17729348758


~]$ awk '/^1/{while((getline var1) <= 0){exit}{print var1}{print $0}}' a.txt
2   Alice   female  24   def@gmail.com  18084925203
1   Bob     male    28   abc@qq.com     18023394012
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

从指定的文件读取数据

  • getline < filename #从文件读取数据,并且读取的数据会保存至$0中,会设置                                      0                          ,                               0,                   0,N,NF

  • getline var < filename #从文件读取数据保存至变量var中,不划分字段不设置变量

~]$ cat test.txt
1-2-3-4-5
2-3-4-5-6
3-4-5-6-1
4-5-6-1-2
5-6-1-2-3
6-1-2-3-4

~]$ awk '{if((getline < "test.txt") > 0){print}}' a.txt ##读取到文件a.txt的第一条记录时就读取test.txt的所有内容
~]$ awk '{while((getline < "test.txt") > 0){print}}' a.txt ##也是读取到a.txt的第一条记录就读取了test.txt的所有内容
`注意:`关闭文件与不关闭文件的区别,不关闭文件的话,读取到a.txt的第一行就读取完了test.txt的内容,并且test.txt的文件指针一直在文件末尾,
因此在循环读取a.txt的后续记录时,输出的test.txt的内容都是空的,因为偏移指针在文件末尾,读取时直接收到EOF而结束读取,因此test.txt
只会被输出一次
~]$ awk '{while((getline < "test.txt") > 0){print};close("test.txt")}' a.txt 
使用close("test.txt")关闭文件后,后续的每次循环都会输出一次test.txt文件的所有行,因此会有66(6*11)行输出
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

从shell命令中读取数据

  • cmd | getline # 无参数读取数据,读取的数据将会被放入$0,会进行变量划分                                      0                          ,                               0,                   0,N,NF

  • cmd | getline var1 #一个参数的getline,将读取的数据存放在变量var1中,不设置变量

~]$ awk '{while(("seq -w 01 05" | getline var1 ) > 0){print var1};close("seq -w 01 05")}' test.txt ##这样就会输出6次1~5,
总共30行
~]$ cat get_num.awk
#!/usr/bin/awk -f
  {
    while(("seq -w 01 05" | getline var1) > 0){
      print var1
     }
      close("seq -w 01 05")
  }
~]$ chmod +x get_num.awk     
~]$ ./get_num.awk test.txt    ##这样运行与上面的命令行模式是一样的

~]$ awk '{if(("date +\"%F %T\"" | getline var1) >0 );print var1;close(get_date)}' a.txt  ##输出时间
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

               
文章知识点与官方知识档案匹配,可进一步学习相关知识
普通分类: