awk用法

awk命令使用
(1)cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
(2)ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
(3)ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
(4)awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
awk内置字符串函数
gsub(r,s) 在整个$0中用s替代r;gsub(r,s,t) 在整个t中用s替代r
gsub函数有点类似于sed查找和替换。它允许替换一个字符串或字符为另一个字符串或字符,并以正则表达式的形式执行。第一个函数作用于记录$0,第二个gsub函数允许指定目标,然而,如果未指定目标,缺省为$0。
index(s,t):函数返回目标字符串s中查询字符串t的首位置。
length(s) :返回s长度
match(s,r): 测试s是否包含匹配r的字符串
split(s,a,fs) 在fs上将s分成序列a
sprint (fmt,exp) :函数类似于printf函数(以后涉及),返回基本输出格式fmt的结果字符串exp。
sub(r,s) 用$0中最左边最长的子串代替s
substr(s,p) 返回字符串s中从p开始的后缀部分
substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分。
match函数测试字符串s是否包含一个正则表达式r定义的匹配。
split使用域分隔符fs将字符串s划分为指定序列a。


1.gsub
要在整个记录中替换一个字符串为另一个,使用正则表达式格式, /目标模式/,替换模式/。例如改变学生序号4842到4899:
$cat grade.txt
M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
P.Bunny 02/99 48 Yellow 12 35 28
J.Troll 07/99 4842 Brown-3 12 26 26
L.Tansl 05/99   4712 Brown-2 12 30 28
# cd /usr/sam
# awk 'gsub(/4842/,4899){print $0}' grade.txt
J.Troll 07/99 4899 Brown-3 12 26 26
2. index
查询字符串s中t出现的第一位置。必须用双引号将字符串括起来。例如返回目标字符串Bunny中ny出现的第一位置,即字符个数。
# awk 'BEGIN {print index("Bunny","ny")}' grade.txt
4
3. length
返回所需字符串长度,例如检验字符串J.Troll返回名字及其长度,即人名构成的字符个数
# awk '$1=="J.Troll" {print length($1)" "$1}' grade.txt
7 J.Troll
还有一种方法,这里字符串加双引号。
# awk 'BEGIN{print length("A FEW GOOD MEN")}'
14
4. match
match测试目标字符串是否包含查找字符的一部分。可以对查找部分使用正则表达式,返回值为成功出现的字符排列数。如果未找到,返回0,第一个例子在ANCD中查找d。因其不存在,所以返回0。第二个例子在ANCD中查找D。因其存在,所以返回ANCD中D出现的首位置字符数。第三个例子在学生J.Lulu中查找u。
# awk 'BEGIN{print match("ANCD",/d/)}'
0
# awk 'BEGIN{print match("ANCD",/D/)}'
4
# awk '$1=="J.Lulu" {print match($1,"u")}' grade.txt
4
5. split
使用split返回字符串数组元素个数。工作方式如下:如果有一字符串,包含一指定分隔符-,例如AD2-KP9-JU2-LP-1,将之划分成一个数组。使用split,指定分隔符及数组名。此例中,命令格式为("AD2-KP9-JU2-LP-1",parts_array,"-"),split然后返回数组下标数,这里结果为4。
# awk 'BEGIN {print split("123-456-789",pats_array,"-")}'
3
还有一个例子使用不同的分隔符。
# awk 'BEGIN {print split("123#456#789",myarray,"#")}'                    
3
这个例子中,split返回数组myarray的下标数。数组myarray取值如下:
myarray[1]=123
myarray[2]=456
myarray[3]=789
6. sub
使用sub发现并替换模式的第一次出现位置。字符串STR包含'poped popo pill',执行下列sub命令sub(/op/,"OP",STR)。模式op第一次出现时,进行替换操作,返回结果如下:'pOPed pope pill'。
如:学生J.Troll的记录有两个值一样,"目前级别分"与"最高级别分"。只改变第一个为29,第二个仍为26不动,操作命令为sub(/26/,"29",$0),只替换第一个出现26的位置。注意J.Troll记录需存在。
# awk '$1=="J.Troll" sub(/26/,"29",$0)' grade.txt
M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 29
P.Bunny 02/99 48 Yellow 12 35 28
J.Troll 07/99 4842 Brown-3 12 29 26
L.Tansl 05/99 4712 Brown-2 12 30 28
7. substr
substr是一个很有用的函数。它按照起始位置及长度返回字符串的一部分。例子如下:
# awk '$1=="L.Tansl" {print substr($1,1,3)}' grade.txt
L.T
上面例子中,指定在域1的第一个字符开始,返回其前面3个字符。
如果给定长度值远大于字符串长度, awk将从起始位置返回所有字符,要抽取LTansl-ey的姓,只需从第3个字符开始返回长度为7。可以输入长度99,awk返回结果相同。
# awk '$1=="L.Tansl" {print substr($1,1,99)}' grade.txt
L.Tansl
substr的另一种形式是返回字符串后缀或指定位置后面字符。这里需要给出指定字符串及其返回字串的起始位置。例如,从文本文件中抽取姓氏,需操作域1,并从第三个字符开始:
# awk '{print substr($1,3)}' grade.txt
Tans
Lulu
Bunny
Troll
Tansl
还有一个例子,在BEGIN部分定义字符串,在END部分返回从第t个字符开始抽取的子串。
# awk 'BEGIN{STR="A FEW GOOD MEN"}END{print substr(STR,7)}' grade.txt
GOOD MEN
8. 从shell中向awk传入字符串
awk脚本大多只有一行,其中很少是字符串表示的。大多要求在一行内完成awk脚本,这一点通过将变量传入awk命令行会变得很容易。现就其基本原理讲述一些例子。
使用管道将字符串stand-by传入awk,返回其长度。
# echo "Stand-by" | awk '{print length($0)}'
8
设置文件名为一变量,管道输出到awk,返回不带扩展名的文件名。
# STR="mydoc.txt"
# echo $STR|awk '{print substr($STR,1,5)}'
mydoc
设置文件名为一变量,管道输出到awk,只返回其扩展名。
# STR="mydoc.txt"
# echo $STR|awk '{print substr($STR,7)}'
txt
字符串屏蔽序列
使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。打印一新行时(新行为字符\n),给出其屏蔽序列,以不失其特殊含义,用法为在字符串前加入反斜线。例如使用\n强迫打印一新行。
如果使用正则表达式,查询花括号({ }),在字符前加反斜线,如/\{/,将在awk中失掉其特殊含义。
awk中使用的屏蔽序列
\b 退格键
\t tab键
\f 走纸换页
\ddd 八进制值
\n 新行
\c 任意其他特殊字符,例如\ \为反斜线符号
\r 回车键
使用上述符号,打印May Day,中间夹tab键,后跟两个新行,再打印May Day,但这次使用八进制数104、141、171分别代表D、a、y。
# awk 'BEGIN {print"\nMay\tDay\n\nMay\t\104\141\171"}'


May     Day


May     Day
注意,\104为D的八进制ASCII码,\141为a的八进制ASCII码,等等。
awk输出函数printf
目前为止,所有例子的输出都是直接到屏幕,除了tab键以外没有任何格式。awk提供函数printf,拥有几种不同的格式化输出功能。例如按列输出、左对齐或右对齐方式。
每一种printf函数(格式控制字符)都以一个%符号开始,以一个决定转换的字符结束.转换包含三种修饰符。
printf函数基本语法是printf([格式控制符],参数),格式控制字符通常在引号里。
printf修饰符
-                 左对齐
Width         域的步长,用0表示0步长
.prec          最大字符串长度,或小数点右边的位数
awk printf格式
%c            ASCII字符
%d           整数
%e           浮点数,科学记数法
%f            浮点数,例如(1 2 3 . 4 4)
%g           awk决定使用哪种浮点数转换e或者f
%o           八进制数
%s           字符串
%x           十六进制数
1. 字符转换
观察ASCII码中65的等价值。管道输出65到awk。printf进行ASCII码字符转换。这里也加入换行,因为缺省情况下printf不做换行动作。
$echo "65" | awk '{printf "%c\n",$0}'
A
按同样方式使用awk得到同样结果。
$awk 'BEGIN{printf "%c\n",65}'
A
所有的字符转换都是一样的,下面的例子表示进行浮点数转换后'999'的输出结果。整数传入后被加了六个小数点。
$awk 'BEGIN{printf "%f\n",999}'
999.000000
2. 格式化输出
打印所有的学生名字和序列号,要求名字左对齐, 15个字符长度,后跟序列号。注意\n换行符放在最后一个指示符后面。输出将自动分成两列。
# awk '{printf "%-15s %s\n",$1,$3}' grade.txt
M.Tans          48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansl         4712
加入一些文本注释帮助理解报文含义。可在正文前嵌入头信息。注意这里使用print加入头信息。如果愿意,也可使用printf。
# awk 'BEGIN{print "Name\t\tS.Number"}{printf "%-15s %s\n",$1,$3}' grade.txt
Name            S.Number
M.Tans          48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansl         4712
打印输出“What is your name?" 利用getline函数从终端接收输入,并传送给name变量,直到用户输入回车为止,如果第一域匹配employees2中的记录。
打印“Found ",name变量,"on line" ,行号。
打印“See ya, ”,name变量
以上是传入name变量的值存在于employees2中的情况
$ awk 'BEGIN{printf "What is your name?" ;\
getline name < "/dev/tty"}\
$1 ~ name {print "Found " name " on line ",NR "."}\
END{print "See ya, " name "."}' employees2
What is your name?Tom
Found Tom on line 1.
See ya, Tom.
不存在于employees2中的情况
$ awk 'BEGIN{printf "What is your name?" ;\
getline name < "/dev/tty"}\
$1 ~ name {print "Found " name " on line ",NR "."}\
END{print "See ya, " name "."}' employees2
What is your name?czm
See ya, czm.


NR和FNR

解释:
FNR:awk当前读取的记录数,其变量值小于等于NR
NR:表示awk开始执行程序后所读取的数据行数。
 
awk 'NR==FNR{a[$0]++} NR>FNR&&!a[$0]' 1.txt 2.txt 找出不同的   awk 'NR==FNR{a[$0]=$0} NR>FNR&&!a[$0]' 1.txt 2.txt 找出不同的
awk 'NR==FNR{a[$0]++} NR>FNR&&a[$0]'  1.txt 2.txt 找出相同的


解释:NR==FNR{a[$0]++} 打开第一个文件的每一行
      NR>FNR&&!a[$0] 打开第二个文件读取每一行是否等于第一文件中的任意一行
      NR==FNR{a[$1]=$0;next}  打开第一个文件,把每行内容存入到a[$1]这个数组。
      NR>FNR{if($1 in a)print $0"\n"a[$1]} 然后打开第二个文件,读取b.txt一行内容,然后插入一行第一个文件的内容。
例子1.
文件passwd:
s2002408030068:x:527:527::/home/dz02/s2002408030068:/bin/pw
s2002408032819:x:528:528::/home/dz02/s2002408032819:/bin/pw
s2002408032823:x:529:529::/home/dz02/s2002408032823:/bin/pw
文件shadow:
s2002408030068:$1$d8NwFclG$v4ZTacfR2nsbC8BnVd3dn1:12676:0:99999:7:::
s2002408032819:$1$UAvNbHza$481Arvk1FmixCP6ZBDWHh0:12676:0:99999:7:::
s2002408032823:$1$U2eJ3oO1$bG.eKO8Zupe0TnyFhWX9Y.:12676:0:99999:7:::

用shadow文件中的密文部分替换passwd中的"x",生一个新passwd文件,如下所示
s2002408030068:$1$d8NwFclG$v4ZTacfR2nsbC8BnVd3dn1:527:527::/home/dz02/s2002408030068:/bin/pw
s2002408032819:$1$UAvNbHza$481Arvk1FmixCP6ZBDWHh0:528:528::/home/dz02/s2002408032819:/bin/pw
s2002408032823:$1$U2eJ3oO1$bG.eKO8Zupe0TnyFhWX9Y.:529:529::/home/dz02/s2002408032823:/bin/pw

CODE:
awk 'BEGIN{OFS=FS=":"} NR==FNR{a[$1]=$2}NR>FNR{$2=a[$1];print}' shadow passwd
NR==FNR,第一个文件shadow,以$1为下标,将$2的值赋给数组a
NR>FNR,第二个文件passwd,将文件shadow$2的值赋值给文件passwd

例子2、
cat file1:
0011AAA 200.00 20050321
0012BBB 300.00 20050621
0013DDD 400.00 20050622
0014FFF 500.00 20050401
cat file2:
I0011  11111
I0012  22222
I0014  55555
I0013  66666
规则:比较 file1的1-4字符 和 file2的2-5 字符,如果相同,将file2 的第二列 与 file1 合并 file3
0011AAA 200.00 20050321 11111
0012BBB 300.00 20050621 22222
0013DDD 400.00 20050622 66666
0014FFF 500.00 20050401 55555
 
CODE:
awk  'NR==FNR{a[substr($1,2,5)]=$2}NR>FNR&&a[b=substr($1,1,4)]{print $0, a[b]}' file2 file1 >file3 如果存在的意思?
awk  'NR==FNR{a[substr($1,2,5)]=$2}NR>FNR&&a[substr($1,1,4)]{print $0, a[substr($1,1,4)]}' b.txt a.txt

结果只有最后一行:(错)
awk  'NR==FNR{c=substr($1,2,5);a[c]=$2;}NR>FNR{b=substr($1,1,4);if(b==c) print $0,a[b] }' c.txt a.txt

例子3、如果文件a中包含文件b,则将文件b的记录打印出来
http://bbs.chinaunix.net/forum/viewtopic.php?t=520411
文件a:
10/05766798607,11/20050325191329,29/0.1,14/05766798607
10/05767158557,11/20050325191329,29/0.08,14/05767158557
文件b:
05766798607
05766798608
05766798609
通过文件a和文件b对比,导出这样的文件出来.
10/05766798607,11/20050325191329,29/0.1,14/05766798607
a

CODE:
awk -F'[/,]' 'ARGIND==1{a[$0]}ARGIND>1{($2 in a);print $0}' b a
awk -F'[/,]' 'NR==FNR{a[$0]}NR>FNR{($2 in a);print $0}' b a
 
例子4、
file1文件内容
 1     0.5  100
 10  15    36.5
file2文件
 50   10    9
 3.2   1     5
将两个文件合成一个文件如:
  51     10.5    109
 13.2   16      41.5
就是对应的字段进行相加以后的数字。

CODE:

awk '{for (i=1;i<=NF;i++) a[i]=$i;getline <"file2";for (i=1;i<NF;i++) printf $i+a[i]" ";printf $NF+a[NF] "\n"}' file1

解析:先获取file2文件中每一个元素,包括最后一列元素,然后逐个循环file1文件中的$1到倒数第二列元素进行相加,然后加空格,最后一列相加之后需要加换行符,所以分开计算结果。

 
例子5、
文件a
1000 北京市 地级 北京市 北京市
1100 天津市 地级 天津市 天津市
1210 石家庄市 地级 石家庄市 河北省
1210 晋州市 县级 石家庄市 河北省
1243 滦县 县级 唐山市 河北省
1244 滦南县 县级 唐山市 河北省
b文件:
110000,北京市
120000,天津市
130000,河北省
130131,平山县
130132,元氏县
这样的字段
a中第二列在b中可能有可能没有,需要把有的匹配起来生成新的一列:要包含a和b的第一列。没有匹配的按照b原来的格式进行输出。
 
CODE:
awk 'BEGIN{FS="[ |,]";OFS=","}NR<=FNR{a[$2]=$1}NR>FNR{print $1,$2,a[$2]}' a b
 
例子6、
file1的第一列与file2的第3列相同,
file1的第二列与file2的第4列的3-5位相同,
file1的第三列与file2的最后一列相同,
# cat file1
AAA  001  1000.00
BBB  001  2000.00
DDD  002  4000.00
EEE  002  5000.00
FFF  003  6000.00
# cat file2
01 1111  AAA  WW001  $$$$  1000.00
02 2222  BBB  GG001  %%%%  2000.00
03 3333  CCC  JJ001  ****  3000.00
04 4444  DDD  FF002  &&&&  4000.00
05 5555  EEE  RR002  @@@@  5000.00
06 666   FFF  UU003  JJJJ  6000.00
07 777   III  II005  PPPP  7000.00
08 8888  TTT  TT008  TTTT  8000.00
 
CODE:
# awk 'NR<=FNR{a[$1]=$1"x"$2"x"$3}
> NR>FNR{b=substr($4,3);c=$3"x"b"x"$6;if(c==a[$3]) print}' file1 file2   ---尽量使用第二个文件的变量
01 1111  AAA  WW001  $$$$  1000.00
02 2222  BBB  GG001  %%%%  2000.00
04 4444  DDD  FF002  &&&&  4000.00
05 5555  EEE  RR002  @@@@  5000.00
06 666   FFF  UU003  JJJJ  6000.00

















































你可能感兴趣的:(awk用法)