Chinaunix首页 | 论坛 | 博客
  • 博客访问: 627971
  • 博文数量: 104
  • 博客积分: 1968
  • 博客等级: 上尉
  • 技术积分: 1587
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-01 17:52
文章分类

全部博文(104)

文章存档

2013年(12)

2012年(50)

2011年(42)

分类: Python/Ruby

2012-07-12 20:57:53

今天在论坛上看到一篇讲awk初学常见问题的帖子,感觉不错和大家分享下,后文有原文链接。


1. awk ‘{code}1’ 中的“1”是干什么的?

一个完整的awk语句为:Awk ‘[patten]{action}……’, 其中pattern缺省为1,action缺省为{print}。

那么awk ‘1’完整的写法就是awk ‘1{print}’; 同理,awk ‘{print}’完整的写法也是awk ‘1{print}’。


2. NR和FNR的区别是啥?

NR: 当前行记录数。

FNR: 当前文件的行记录数。

当awk处理的文件数超过1时,NR和FNR才会有区别。例如:

  1. cat file
  2. a
  3. b
  4. c
  5. d
  6. e
  7. f

  8. awk '{print "NR = " NR "  FNR = " FNR, $0}' file
  9. NR = 1  FNR = 1 a
  10. NR = 2  FNR = 2 b
  11. NR = 3  FNR = 3 c
  12. NR = 4  FNR = 4 d
  13. NR = 5  FNR = 5 e
  14. NR = 6  FNR = 6 f

  15. awk '{print "NR = " NR "  FNR = " FNR, $0}' file file
  16. NR = 1  FNR = 1 a
  17. NR = 2  FNR = 2 b
  18. NR = 3  FNR = 3 c
  19. NR = 4  FNR = 4 d
  20. NR = 5  FNR = 5 e
  21. NR = 6  FNR = 6 f
  22. NR = 7  FNR = 1 a
  23. NR = 8  FNR = 2 b
  24. NR = 9  FNR = 3 c
  25. NR = 10  FNR = 4 d
  26. NR = 11  FNR = 5 e
  27. NR = 12  FNR = 6 f


3. Awk怎么引入变量?

有两种方法:

<1>: awk -v var=$VAR '{code}'
       <2>: awk '{CODE}'$VAR'{CODE}'
例如:

  1. VAR=XXX

  2. awk -v var=$VAR 'BEGIN{print var}'
  3. XXX

  4. awk 'BEGIN{print "'$VAR'"}'
  5. XXX

我推荐使用第一种方法,这样可以避免一些不必要的烦恼。


4. 为什么OFS不起作用?

先看一个例子:

  1. echo 'aaa bbb ccc ddd
  2. aaa bbb ccc ddd
  3. aaa bbb ccc ddd
  4. aaa bbb ccc ddd' |awk -v OFS="|" '{print $0}'
  5. aaa bbb ccc ddd
  6. aaa bbb ccc ddd
  7. aaa bbb ccc ddd
  8. aaa bbb ccc ddd

上面的例子中OFS为什么没有生效呢,原因是OFS指的是输出字段分隔符,

所以必须对字段进行操作时OFS才会起作用,正确的方法应该是:

  1. echo 'aaa bbb ccc ddd
  2. aaa bbb ccc ddd
  3. aaa bbb ccc ddd
  4. aaa bbb ccc ddd' |awk -v OFS="|" '{$1=$1;print $0}'
  5. aaa|bbb|ccc|ddd
  6. aaa|bbb|ccc|ddd
  7. aaa|bbb|ccc|ddd
  8. aaa|bbb|ccc|ddd

正如Tim大师所讲的,$1=$1这个action,是我们对awk撒的谎,目的就是为了使得OFS生效,

除此之外,NF =0也是常用的方法。参考:



5. 同样的代码,别人运行成功,为什么我运行失败?

这个问题的原因很多,我这里列举两个最常见的,大家可以补充。

<1>: awk版本引起的,如gawk中的一些扩展函数或变量,在nawk中没有,

或是不同版本的(g/n)awk也会有差别,这样情况需要重新编写。

<2>: 文本格式的问题,cat-A file查看一下,如果是,dos2unix应该可以解决。

注:书写错误也有可能哦


6. Awk 语句中可以使用{n,m}这样的正则么?

可以,使用方法:gawk -- re-interval ,其它版本使用方法会有所不同,请大家补充


7. BEGIN 和END 到底是怎么一回事?

有时,对于新手可能也会是个问题。简单说下:

BEGIN {action} : 读取文本之前进行的操作。要避免类似下面的写法:

  1. awk 'BEGIN{ filename =  FILENAME}' file
  2. # or:
  3. awk 'BEGIN{FS=":"; for(i=2;i<=NF;i ) print $i}' file


   如果BEGIN 模块中使用getline函数时,情况会有所不同:
  1. cat file
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5

  7. awk 'BEGIN{while (getline <"file") print}' file
  8. 1
  9. 2
  10. 3
  11. 4
  12. 5

END {action}: 
它在整个输入文件处理完成后被执行,同样无法对文本进行任何操作,如匹配某个pattern执行action。


8. print,printf 和sprintf?

print:为一般的打印

printf:可以定义打印格式

sprintf:可以完成和printf相同的功能,不同的是sprintf只能输出值,并不能完成打印的功能。

       print默认有个换行\n,
       而printf没有,当然它和C语言的printf类似(awk本是c的近亲),能打印各种格式,但默认没有换行。

例如:

  1. awk 'BEGIN{var=123; print "var = " var}'
  2. var = 123

  3. awk 'BEGIN{var=123;printf "%s _\n", "var =",var}'
  4. var = 123.000000

  5. awk 'BEGIN{var=123;sprintf ("%s  _\n", "var =",var)}'


  6. awk ‘BEGIN{var1=123;var2=sprintf ("_",var1); print "var2 =" var2}’
  7. var2 = 123.000000


9. “a==b?c:d” ?

这个是一个if语句的简写,即conditional expression1 ? expression2: expression3;完整写法为:

if(a==b) {c} else {d}


10. awk ‘! a[$0] ’ 怎么理解?

这是一个非常经典的去重复项的awk语句,虽然短小,不过涉及到了不少知识点,下面一一解读:

<1> :”!” 即非。

<2>:a[$0],以$0为数据下标,建立数组a

<3>:a[$0] ,即给数组a赋值,a[$0] =1

<4> :那么组合起来,awk是怎么执行!a[$0] 的呢?我用一个实际例子来解释:

  1. cat file
  2. 111
  3. 222
  4. 111
  5. 222
  6. 333

  7. awk '{print a[$0],!a[$0] ,a[$0],!a[$0],$0}' file
  8.   1 1 0 111
  9.   1 1 0 222
  10. 1 0 2 0 111
  11. 1 0 2 0 222
  12.   1 1 0 333


原来,第一个a[$0]的值为空,所以!a[$0] 是先作判断,结果为1(非空为真,即为1),

再作数组赋值a[$0] 。这也就是为什么前面的!a[$0] 并不一定等于后面的!a[$0]。

awk ‘ a[$0]==1’ 和上面的代码作用一样,你理解了么?


11. 如何打印单双引号?

  1. awk 'BEGIN {print "single quote --> '\''";print "double quote --> \"" }'
  2. single quote --> '
  3. double quote --> "



更可靠的的方法如Tim所示:
  1. awk 'BEGIN {print "single quote --> \047";print "double quote --> \042" }'

12. awk 语句中多个{}是怎么执行的?

还是用个例子来说明:

  1. cat file
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5

  7. awk '$1==3{printf "|| "$0}{printf " @@ "$0}{print $0}' file # 这个语句中包含三个action
  8. @@ 11   # 判断$1==3?否;执行 action {printf " @@ "$0};执行 action {print $0}
  9. @@ 22   # 判断$1==3?否;执行 action {printf " @@ "$0};执行 action {print $0}
  10. || 3 @@ 33  # 判断$1==3?是,执行{print “|| “$0}; 执行 action {printf " @@ "$0};执行 action {print $0}
  11. @@ 44  # 判断$1==3?否;执行 action {printf " @@ "$0};执行 action {print $0}
  12. @@ 55  # 判断$1==3?否;执行 action {printf " @@ "$0};执行 action {print $0}

这样可以清楚的看出,awk是一行一行读取文本,然后按照代码的前后顺序执行。

但如果action中包含next或exit时,有所不同:

  1. awk '$1==3{printf "|| "$0;next}{printf "@@ "$0}{print $0}' file
  2. @@ 11
  3. @@ 22
  4. || 3@@ 44
  5. @@ 55

  6. awk '$1==3{printf "|| "$0;exit}{printf "@@ "$0}{print $0}' file
  7. @@ 11
  8. @@ 22
  9. || 3


13. FS, OFS, RS, ORS?

最后用图解的方式说明一下这四个变量:

Picture2.png


转自CU 论坛,原文链接:

阅读(2326) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~