[SHELL]awk的用法举例

从初学awk到现在小有所成,非常感谢CUers的帮助,总结了下自己曾经遇到的问题和犯的错误,供初学者借鉴,因本人非计算机专业,对专业词汇可能有表述不对的地方,还请指正和补充!


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

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

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


2. NRFNR的区别是啥?

NR: 当前行记录数。

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

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

点击(此处)折叠或打开

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

3. Awk怎么引入变量?

有两种方法:

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

 

点击(此处)折叠或打开

  1. 1.VAR=XXX
  2. 2.
  3. 3.awk -v var=$VAR 'BEGIN{print var}'
  4. 4.XXX
  5. 5.
  6. 6.awk 'BEGIN{print "'$VAR'"}'
  7. 7.XXX
  我推荐使用第一种方法,这样可以避免一些不必要的烦恼。如http://bbs.chinaunix.net/thread-1835620-1-1.html


  

4. 为什么OFS不起作用?

先看一个例子:
 

点击(此处)折叠或打开

  1. 1.echo 'aaa bbb ccc ddd
  2. 2.aaa bbb ccc ddd
  3. 3.aaa bbb ccc ddd
  4. 4.aaa bbb ccc ddd' |awk -v OFS="|" '{print $0}'
  5. 5.aaa bbb ccc ddd
  6. 6.aaa bbb ccc ddd
  7. 7.aaa bbb ccc ddd
  8. 8.aaa bbb ccc ddd
上面的例子中OFS为什么没有生效呢,原因是OFS指的是输出字段分隔符,所以必须对字段进行操作时OFS才会起作用,正确的方法应该是:



点击(此处)折叠或打开

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

正如Tim大师所讲的,$1=$1这个action,是我们对awk撒的谎,目的就是为了使得OFS生效,除此之外,NF+=0也是常用的方法。参考:http://bbs.chinaunix.net/viewthr ... p;extra=&page=1

   

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. 1.awk 'BEGIN{ filename =  FILENAME}' file
  2. 2.# or:
  3. 3.awk 'BEGIN{FS=":"; for(i=2;i<=NF;i++) print $i}' file
  

如果BEGIN 模块中使用getline函数时,情况会有所不同:

  

点击(此处)折叠或打开

  1. 1.cat file
  2. 2.1
  3. 3.2
  4. 4.3
  5. 5.4
  6. 6.5
  7. 7.
  8. 8.awk 'BEGIN{while (getline <"file") print}' file
  9. 9.1
  10. 10.2
  11. 11.3
  12. 12.4
  13. 13.5

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

8. printprintf sprintf

print:为一般的打印

printf:可以定义打印格式

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

 

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

例如:


 

点击(此处)折叠或打开

  1. 1.awk 'BEGIN{var=123; print "var = " var}'
  2. 2.var = 123
  3. 3.
  4. 4.awk 'BEGIN{var=123;printf "%s %5f\n", "var =",var}'
  5. 5.var = 123.000000
  6. 6.
  7. 7.awk 'BEGIN{var=123;sprintf ("%s  %5f\n", "var =",var)}'
  8. 8.
  9. 9.
  10. 10.awk ‘BEGIN{var1=123;var2=sprintf ("%5f",var1); print "var2 =" var2}’
  11. 11.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. 1.cat file
  2. 2.111
  3. 3.222
  4. 4.111
  5. 5.222
  6. 6.333
  7. 7.
  8. 8.awk '{print a[$0],!a[$0]++,a[$0],!a[$0],$0}' file
  9. 9.  1 1 0 111
  10. 10.  1 1 0 222
  11. 11.1 0 2 0 111
  12. 12.1 0 2 0 222
  13. 13.  1 1 0 333
  

原来,第一个a[$0]的值为空,所以!a[$0]++是先作判断,结果为1(非空为真,即为1),再作数组赋值a[$0]++。这也就是为什么前面的!a[$0]++并不一定等于后面的!a[$0]

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

  

11. 如何打印单双引号?

  

点击(此处)折叠或打开

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

点击(此处)折叠或打开

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

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

还是用个例子来说明:

  

点击(此处)折叠或打开

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

这样可以清楚的看出,awk是一行一行读取文本,然后按照代码的前后顺序执行。但如果action中包含nextexit时,有所不同:

 

点击(此处)折叠或打开

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


 13. FS, OFS, RS, ORS?

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



14.
Awk 内置的字符串函数

gsub(r,s)

在整个$0中用s代替r

gsub(r,s,t)

在整个t中用s替代r

index(s,t)

返回s中字符串t的第一位置

length(s)

返回s长度

match(s,r)

测试s是否包含匹配r的字符串

split(s,a,fs)

在fs上将s分成序列a

sprint(fmt,exp)

返回经fmt格式化后的exp

sub(r,s)

用$0中最左边最长的子串代替s

substr(s,p)

返回字符串s中从p开始的后缀部分

substr(s,p,n)

返回字符串s中从p开始长度为n的后缀部分

gsub函数有点类似于sed查找和替换。它允许替换一个字符串或字符为另一个字符串或字符,并以正则表达式的形式执行。第一个函数作用于记录$0,第二个gsub函数允许指定目标,然而,如果未指定目标,缺省为$0。

index(s,t)函数返回目标字符串s中查询字符串t的首位置。length函数返回字符串s字符长度。

match函数测试字符串s是否包含一个正则表达式r定义的匹配。

split使用域分隔符fs将字符串s划分为指定序列a。

sprint函数类似于printf函数,返回基本输出格式fmt的结果字符串exp。

sub(r,s)函数将用s替代$0中最左边最长的子串,该子串被r匹配。

substr(s,p)返回字符串s在位置p后的后缀。

substr(s,p,n)同上,并指定子串长度为n。

此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。 

awk中的gsub的&,表示要被替换的原始字符。gsub(/[0-9]+/,”\\0x&”),这时&表示[0-9]所匹配到的字符。

 

15.awk常见错误检查
当第一次使用awk时,可能被错误信息搅得不知所措,但通过长时间和不断的学习,可总
结出以下规则。在碰到 awk错误时,可相应查找:
? 确保整个awk命令用单引号括起来。

? 确保命令内所有引号成对出现。
? 确保用花括号括起动作语句,用圆括号括起条件语句。
? 可能忘记使用花括号,也许你认为没有必要,但 awk不这样认为,将按之解释语法。

?正则表达式用斜线括起来!      \ ^ $ . [] | () * + ?






ARGC:支持命令行中传入 a w k脚本的参数个数。

ARGV:是ARGC的参数排列数组,其中每一元素表示为ARGV[n], n为期望访问的命令行参数。
ENVIRON :支持系统设置的环境变量,要访问单独变量,使用实际变量名,例如
ENVIRON [“ EDITOR”] =“Vi”。
FILENAME:支持awk脚本实际操作的输入文件。

因为awk可以同时处理许多文件,因此如果访问了这个变量,将告之系统目前正在浏览的实际文件。
FNR:支持awk目前操作的记录数。其变量值小于等于 NR。如果脚本正在访问许多文件,
每一新输入文件都将重新设置此变量。
FS:用来在awk中设置域分隔符,与命令行中 - F选项功能相同。缺省情况下为空格。

如果用逗号来作域分隔符,设置 FS = ","。
NF:支持记录域个数,在记录被读之后再设置。
OFS:允许指定输出域分隔符,缺省为空格。如果想设置为 #,写入OFS = "#"。

ORS:为输出记录分隔符,缺省为新行(\n)。
RS:是记录分隔符,缺省为新行 (\n)。


16.
awk操作符



域值比较操作
有两种方式测试一数值域是否小于另一数值域。
1) 在BEGIN中给变量名赋值。
2) 在关系操作中使用实际数值。
通常在BEGIN部分赋值是很有益的,可以在awk表达式进行改动时减少很多麻烦。
使用关系操作必须用圆括号括起来。

 

AWK内置字符串函数



 

从shell中向awk传入字符串

 

(1) 使用管道将字符串stand-by传入awk,返回其长度。

(2) 设置文件名为一变量,管道输出到awk,返回不带扩展名的文件名。

(3) 设置文件名为一变量,管道输出到awk,只返回其扩展名。

字符串屏蔽序列


printf修饰符



向一行awk命令传值
在查看awk脚本前,先来查看怎样在 awk命令行中传递变量。
在awk执行前将值传入awk变量,需要将变量放在命令行中,格式如下:
awk 命令变量=输入文件值

 

在awk中使用F S变量

 

使用awk脚本时,记住设置 FS变量是在 BEGIN部分。

 

向awk脚本传值

格式:awk script_file var=value input_file

 

awk数组

数组使用前,不必定义,也不必指定数组元素个数。经常使用循环来访问数组。下面是
一种循环类型的基本结构:for (element in array )  print array[element]






posted @ 2017-04-18 14:10  foreverfriends  阅读(591)  评论(0编辑  收藏  举报