awk教程

教程一

9.1    调用awk
三种方式:
1.    命令行方式:    
awk [-F filed-separator] 'commands' input-files
-F    指定分隔符(默认是空格或tab)
commands    awk的命令
input-files    要处理的文件
2.    将所有awk命令插入一个文件,并使awk程序可执行,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它
3.    将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-files
-f    指明调用脚本名
input-files    待处理的文件

9.2    awk脚本
在命令中调用awk时,awk脚本由各种操作和模式组成。
awk每次读一条记录或一行,并使用指定的分隔符分隔指定域。当新行出现时,awk命令获悉已读完整条记录,然后在下一个记录启动读命令,这个读进程将持续到文件尾或文件不再存在。
9.2.1    模式和动作
任何awk语句都由模式和动作组成。模式部分决定动作语句何时触发及触发条件。处理即对数据进行的操作。如果省略模式部分,动作将时刻保持执行状态。
模式可以是任何条件语句、复合语句或正则表达式,包括两个特殊字段BEGIN和END。使用BEGIN语句设置计数和打印头。BEGIN语句用在任何文本浏览动作之前,之后文本浏览动作依据输入文件开始执行。END语句用在awk完成文本浏览动作后打印输出文本总数和结尾状态标志。如果不特别指明模式,awk总是匹配。
实际动作在大括号{}内指明。动作大多数用来打印,但还有些更长的代码诸如if和循环语句及循环退出结构。如果不指明采取动作,awk将打印出所有浏览出来的记录。
9.2.2    域和记录
awk执行时,其浏览域标记为$1,$2…$n,这种方法称为域标识。当需要指定多域时使用逗号,用于分隔,如$1,$3指定第一域和第三域,如果希望指定所有域可使用$0。
使用print命令执行打印操作,这是一个awk命令,需要用{}括起来。
1.    抽取域
举例: 现有一个grade.txt文件,内容如下:
$ cat grade.txt
M.Tansley        05/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.Tansley        05/99    4712    Brwon-2    12    30    28
此文本文件有7个域,以空格作为域分隔符
2.    保存awk输出
两种方式保存awk的输出结果:
重定向到文件:(屏幕无显示)
$ awk '{print $0}' grade.txt >wow
使用管道将输出结果传给tee:(屏幕显示结果)
$ awk '{print $0}' grade.txt|tee woww
3.    使用标准输入
几种方法:
$ belts.awk grade.txt
$ belts.awk < grade.txt
4.    打印所有记录
$ awk '{print $0}' grade.txt
5.    打印单独记录
只打印$1和$4:
$ awk '{print $1,$4}' grade.txt
6.    自定义格式打印
可以在$1和$4的上方添加注释,Name和Belt:
$ awk 'BEGIN {print "Name\t\tBelt\n-------------------------"} {print $1"\t"$4}' grade.txt
在结尾加上结束注释:
$ awk 'BEGIN {print "Name\t\tBelt\n-------------------------"} {print $1"\t"$4} END {print "-------------------------\nEnd of report"}' grade.txt
7.    awk错误信息提示
在碰到awk错误时,可相应查找:
•    确保整个awk命令用单引号括起来
•    确保命令内所有引号成对出现
•    确保用大括号{}括起动作语句,用括号()括起条件语句
•    可能忘记使用大括号{}
8.    awk键盘输入
如果没有给出输入文件,awk从键盘获得输入,完成后按<Ctrl-D>结束输入
9.2.3    元字符
\ ^ $ . [ ] | ( ) * + ?
其中+和?只适用于awk而不适用于grep或sed:
+    匹配一个或一个以上前面的单字符
?    匹配0个或一个前面的单字符
举例:
/XY+Z/    匹配XYZ、XYYYYZ
/XY?Z/    匹配XYZ、XZ
9.2.4    条件操作符
操作符            描述
  <                小于
  <=              小于等于
  ==                等于
  !=               不等于
  >                大于
  >=              大于等于
  ~           匹配正则表达式
  !~          不匹配正则表达式
1.    匹配
使用~紧跟正则表达式可以匹配域,也可以用if,条件需要用()括起来
举例:
查询棕带学员的所有情况(打印出$4匹配Brown的行)
$ awk '{if ($4~/Brown/) print $0}' grade.txt

$ awk '$0 ~ /Brown/' grade.txt
2.    精确匹配
使用==并用双引号括起条件可以精确匹配条件
举例:
$ awk '{if ($3 == "48") print $0}' grade.txt
3.    不匹配
使用!~紧跟正则表达式不匹配域
举例:
查询不是棕带的所有学员情况(打印出$4不匹配Brown的行)
$ awk '{if ($4!~/Brown/) print $0}' grade.txt

$ awk '$0 !~ /Brown/' grade.txt
4.    比较
由于几个比较大小符的使用方法都一样,就随便举一个例子:
$ awk '{if ($6 < $7) print $1" try better at the next comp"}' grade.txt
5.    各种匹配
匹配Green或green:
$ awk '/[Gg]reen/' grade.txt
匹配$1的第四个字符是a:
$ awk '$1 ~ /^...a/' grade.txt
匹配Yellow或Brown:
$ awk '$4 ~ /Yellow|Brown/' grade.txt
匹配以J开头的行:
$ awk '$0 ~ /^J/' grade.txt
6.    复合表达式
复合模式或复合操作符用于形成复杂的逻辑操作,复合表达式即为模式间通过使用复合操作符互相结合起来的表达式
&&    AND:    符号两边必须同时为真
|| OR:    符号两边至少一边为真
! :    非 求逆
举例:
$ awk '{if ($1 == "P.Bunny" && $4 == "Yellow") print $0}' grade.txt
$ awk '{if ($4 == "Yellow" || $4 ~ /Brown/) print $0}' grade.txt
9.2.5    awk内置变量
awk有许多内置变量用来设置环境信息,常用的有:
ARGC        命令行参数个数
ARGV        命令行参数排列
ENVIRON        支持队列中系统环境变量的使用
FILENAME    awk读取的文件名
FNR            当前文件已处理的记录行数
FS            设置域分隔符,相当于-F
NF            域的列数
NR            已处理的记录总行数
OFS            设置输出字段域分隔符
RS/ORS        换行符

ARGC支持命令行中传入awk脚本的参数个数。ARGV是ARGC的参数排列数组,其中每一元素表示为ARGV[n],n为希望访问的命令行参数
ENVIRON支持系统设置的环境变量,要访问单独变量,使用实际变量名,如ENVIRON[“EDITOR”]=”Vi”
FILENAME为awk脚本当前操作文件的文件名
FNR为awk当前操作文件的记录行数,其值总是小于等于NR。如果脚本正在访问多个文件,每一新输入文件都将重置此变量
FS用来设置域分隔符,与命令行中-F相同,缺省为空格。如: 以冒号为分隔符FS=":"
NF为记录域个数(列数),在记录被读之后设置,常用$NF指定最后一列
OFS指定输出记录的域分隔符,缺省为空格。如: 以-为分隔符输出FS="-"
ORS与RS都为输出记录分隔符,缺省是新行(\n)
举例:
查看文件的记录数:
$ awk 'END {print NR}' grade.txt
打印所有记录及记录的行号及总域数,并在最后打印出读取文件的文件名:
$ awk '{print NF,NR,$0} END {print FILENAME}' grade.txt
至少包含一个记录且包含Brown:
$ awk '{if (NR > 0 && $4 ~ /Brown/) print $0}' grade.txt
NF的一个强大功能是将变量$PWD的返回值传入awk并显示其目录:
$ echo $PWD | awk -F/ '{print $NF}'
显示文件名:
$ echo "/usr/apache/conf/httpd.conf" | awk -F/ '{print $NF}'
9.2.6    awk操作符
awk操作符的基本表达式可以划分为数字型、字符串型、变量型域及数组元素
= += -= *= /= %= ^=            赋值操作符
?                        条件表达操作符
|| && !                    并、与、非
~ !~                        匹配操作符(匹配与不匹配)
< <= == != > >=                关系操作符
+ - * / % ^                算术操作符
++ --                        前缀和后缀
1.    设置输入域到域变量名
在awk中,设置有意义的域名是一种好习惯,在进行模式匹配或关系操作时更容易理解。一般的变量名设置方式为name=$n,这里name为调用的域变量名,n为实际域号。多个域名设置之间用分号;分隔(请注意下面;的使用)
$ awk '{name = $1;belts = $4; if (belts ~ /Yellow/) print name" is belt "belts}' grade.txt
2.    域值比较操作
有两种方式测试一数值域是否小于另一数值域:
1)    在BEGIN中给变量名赋值
2)    在关系操作符中使用实际数值
通常在BEGIN部分赋值是很有益的,可以在awk表达式进行改动时减少很多麻烦。使用关系操作时必须用圆括号括起来。举例:
查询所有比赛中得分在27点一下的学生:
$ awk '{if ($6 < 27) print $0}' grade.txt

$ awk 'BEGIN {BASELINE = "27"} {if ($6 < BASELINE) print $0}' grade.txt
3.    修改数值域取值
当在awk中修改任何域时,重要的一点是要记住实际输入文件是不可修改的,修改的只是保存在缓存里的awk复本。awk会在变量NR或NF中反映出修改痕迹
为修改数值域,简单的给域标识重赋新值。举例:
$ awk '{if ($1 == "M.Tansley") $6 = $6 - 1; print $1,$6,$7}' grade.txt
4.    修改文本域
修改文本域即对其重新赋值,赋给一个新的字符串。记住,字符串要使用双引号,并用圆括号括起整个语法。举例:
$ awk '{if ($1 == "J.Troll") ($1 = "J.L.Troll"); print $1}' grade.txt
5.    只显示修改记录
如果文件很大,修改的记录很多,所以需要只查看修改部分。在模式后面使用大括号{}将只打印修改部分。取得模式,再根据模式结果实施操作。举例:(注意大括号的位置)
$ awk '{if ($1 == "J.Troll") {$1 = "J.L.Troll"; print $1}}' grade.txt
6.    创建新的输出域
在awk中处理数据时,基于各域进行计算时创建新域是一种好习惯。创建新域要通过其他域赋予新域标识符。举例:
在grade.txt中创建新域8保存域目前级别分与域最高级别分的差值:
$ awk 'BEGIN {print "Name\tDifference"} {if ($6 < $7) {$8 = $7 - $6; print $1,$8}}' grade.txt
或者赋予便于理解的变量名:
$ awk 'BEGIN {print "Name\tDifference"} {if ($6 < $7) {diff = $7 - $6; print $1,diff}}' grade.txt
7.    增加列值
使用符号+=增加列数或进行运行结果统计。将符号右边的变量域的值赋给左边。
举例:
打印出所有学生的总成绩(将整个文件的$6求和,total为变量名):
$ awk '(total += $6); END {print "Club student total points: "total}' grade.txt
如果文件很大,只想打印结果部分而不是所有记录,在语句的外面加上大括号{}即可:
$ awk '{(total += $6)}; END {print "Club student total points: "total}' grade.txt
查看当前目录所有文件大小及总和(除去子目录):
$ ls -l|awk '/^[^d]/ {print $9"\t"$5} {total += $5} END {print "total Bytes: "total}'
9.2.9    内置的字符串函数
awk有很多强大的字符串函数:
gsub(r,s,t)                在整个字符串t中用字符串s替代所有满足正则表达式r的字符串(如没指定t则默认为$0)
index(s,t)                返回字符串s中字符串t第一次出现的位置(如不存在则为0)
length(s)                返回s字符串的长度(如没指定s则默认为$0)
match(s,r)            返回第一个满足正则表达式r的字符串在s字符串里面的位置(如无匹配的则为0)
split(s,a,sep)            使用sep将字符串s分隔成为数组a的元素,返回数组元素的数量(如果没指定分隔符则默认与FS相同用法)
sprint("fmt",exp)        使用printf的格式说明对表达式exp 进行格式化输出
sub(r,s,t)                在字符串t中用s字符串替换满足正则表达式r的第一个字符串,返回1如果成功,否则返回0(如没指定t则默认为$0)
substr(s,p,n)            返回字符串s中以p位置开始长度为n的字符串(如果没指定n则返回从p位置开始的所有字符串)
tolower(s)            将字符串s中的所有大写字母转换为小写,返回转换后的字符串
toupper(s)            将字符串s中的所有小写字母转换为大写,返回转换后的字符串
1.    gsub(r,s,t)
在整个字符串t中用字符串s替代所有满足正则表达式r的字符串(如没指定t则默认为$0):
$ awk 'gsub(/4842/,4899) {print $0}' grade.txt

$ awk '{if (gsub(/4842/,4899)) print $0}' grade.txt
2.    index(s,t)
返回字符串s中字符串t第一次出现的位置(如不存在则为0)。必须用双引号将字符串都括起来:
$ awk 'BEGIN {print index("Benny","ny")}' grade.txt
3.    length(s)
返回s字符串的长度(如没指定s则默认为$0):
$ awk '$1 == "J.Troll" {print length($1)" "$1}' grade.txt
$ awk 'BEGIN {print length("Kevin is a good boy.")}'
4.    match(s,r)
返回第一个满足正则表达式r的字符串在s字符串里面的位置:
$ awk 'BEGIN {print match("ANCD",/d/)}'(返回0)
$ awk '$1=="J.Lulu" {print match($1,/u/)}' grade.txt(返回第一个u在J.Lulu里的位置: 3)
5.    split(s,a,sep)
使用sep将字符串s分隔成为数组a的元素,返回数组元素的数量:
$ awk 'BEGIN {print split("123#456#789",array,"#")}'
返回3,数组array的元素分别为:
array[1]="123"
array[2]="456"
array[3]="789"
6.    sub(r,s,t)
在字符串t中用s字符串替换满足正则表达式r的第一个字符串,返回1如果成功,否则返回0(如没指定t则默认为$0):
$ awk '$1 == "J.Troll" {if (sub(/26/,"29")) print}' grade.txt
7.    substr(s,p,n)
返回字符串s中以p位置开始长度为n的字符串(如果没指定n则返回从p位置开始的所有字符串):
$ awk '$1 == "L.Tansley" {print substr($1,1,5)}' grade.txt(返回L.Tan)
如果给定长度值n大于字符串长度,则awk将从起始位置返回所有字符:
$ awk '$1 == "L.Tansley" {print substr($1,3,15)}' grade.txt(返回Tansley)
如果没指定n,则awk将从起始位置返回所有字符:
$ awk '{print substr($1,3)}' grade.txt
在BEGIN部分定义字符串,在END部分返回抽取的字符:
$ awk 'BEGIN {STR="Kevin is a good boy."} END {print substr(STR,12,8)}' grade.txt
8.    从shell中向awk传入字符串
$ echo "Stand-by"|awk '{print length($0)}'
设置文件名为一变量,取文件名:
$ STR="grade.txt"
$ echo $STR|awk '{print substr($STR,1,5)}'
取文件名后缀:
$ STR="grade.txt"
$ echo $STR|awk '{print substr($STR,7) }'
9.2.10    awk输出函数printf
awk提供函数printf,拥有几种不同的格式化输出功能。每一种printf函数(控制格式字符)都以一个%符号开始,以一个决定转换的字符结束。转换包含三种修饰符。
语法:
printf "格式控制符",参数

awk printf修饰符
-        左对齐
Width    域的步长,用0表示0步长
.prec    最大字符串长度,或小数点右边的位数

awk printf格式
%c        ASCII字符
%d        整数
%e        浮点数(科学记数法)
%f        浮点数
%g        awk决定使用哪种浮点数转换(e或者f)
%o        八进制数
%s        字符串
%x        十六进制数
举例:
字符转换:
$ awk 'BEGIN {printf "%c\n",65}' grade.txt
格式化输出:
打印所有的学生名字和序列号,要求名字左对齐,15个字符长度,后跟序列号:
$ awk '{printf "%-15s %s\n",$1,$3}' grade.txt
再加入注释:
$ awk 'BEGIN {print "Name\t\tNumber"} {printf "%-15s %s\n",$1,$3}' grade.txt
9.2.11    向一行awk命令传值
在awk执行前将值传入awk变量,需要将变量放在命令行下,格式:
awk 命令变量=输入文件值
举例:
$ awk '{if ($5 < AGE) print $0}' AGE=10 grade.txt
查询可用空间小于36000M的分区:
$ df -m|awk '($4 ~ /^[0-9]/) {if ($4 < LIMIT) print $6"\t"$4}' LIMIT=36000
awk也允许传入环境变量。举例:
查询当前用户登陆在哪个端口:
$ who|awk '{if ($1 == user) print $1" you are connected to "$2}' user=$LOGNAME
9.2.12    awk脚本文件
可以将awk脚本写入一个文件再执行它。使用awk脚本的好处是不比每次使用时都需要重新输入,并且可以增加注释便于理解。拿一个awk脚本举例:
#!/bin/awk -f
# all comment lines must start with a hash '#'
# name: student_total.awk
# to call: student_total.awk grade.txt
# prints total and average of club student points

# print a header first
BEGIN{
print "Student\t\tDate\tNumber\tGrade\tAge\tPoints\tMax"
print "Name\t\tJoined\t\t\t\tGained\tPoint Available"
print "========================================================================"
}

# let's add the scores of points gained
(total += $6)

# finished processing now let's print the total and average point
END {
print "Club Student Total points: " total
print "Average Club Student points: " total/NR
}
第一行是#!/bin/awk -f,这一行很重要,没有它脚本将不能执行,因为它告知脚本系统中awk的位置。通过将命令分开,脚本的可读性提高,还可以在命令之间加入注释。
执行时在脚本文件后键入文件名,但需要先赋予可执行权限。
9.2.13    在awk中使用FS变量
使用awk脚本时,设置FS变量是在BEGIN部分。如果不这样,awk不知道域分隔符是什么。
脚本举例:(该脚本从/etc/passwd中抽取第一和第五域)
#!/bin/awk -f
# to call: passwd.awk /etc/passwd
# print out the first and fifth fields
BEGIN {
FS=":"}
{print $1,"\t",$5}

9.2.14    向awk脚本传值
向awk脚本传值与向awk命令行传值方式大体相同,格式:
awk_script var=value input_file
举例:
#!/bin/awk -f
# name: age.awk
# to call: age.awk AGE=n grade.txt
# prints ages that are lower than the age supplied on the command line
{if ($5 < AGE)
print $0}
执行方式:(别忘了先赋予可执行权限)
$ ./age.awk AGE=10 grade.txt
也可以使用管道命令将命令的结果传递给awk脚本,如
$ cat grade.txt |./ student_total.awk
9.2.15    awk数组
数组使用前不必定义,也不必指定数组元素个数。经常使用循环来访问数组,下面是一种循环类型的基本结构:
for (element in array) print array[element]
举例:(前面提到过的字符串123#456#789)
#!/bin/awk -f
# name: arraytest.awk
# prints out an array
BEGIN {
record="123#456#789";
split(record,array,"#")
}
END {
for (i in array) {
print array[i]
}
}
使用/dev/null作为输入运行脚本:
$ ./arraytest.awk /dev/null

从指定文本里找出匹配条件的项及其出现的次数
#!/bin/awk -f
# name: count.awk
# to call: count.awk grade2.txt
# loops through the grade2.txt file and counts how many belts we have in(yellow, orange, red)
# also count how many adults and juniors we have
# start of BEGIN
# set FS and load the arrays with our values
BEGIN {FS="#"
# load the belt colours we are interested in only
belt["Yellow"]
belt["Orange"]
belt["Red"]
# end of BEGIN
# load the student type
student["Junior"]
student["Senior"]
}
# loop thru array that holds the belt colours against field-1
# if we have a match, keep a running total
{for (colour in belt)
  {if ($1 == colour)
  belt[colour]++}}
# loop thru array that holds the student type against
# field-2 if we have a match, keep a running total
{for (senior_or_junior in student)
  {if ($2 == senior_or_junior)
  student[senior_or_junior]++}}

# finished processing so print out the matches..for each array
END {for (colour in belt) print "The club has", belt[colour], colour, "Belts"

for (senior_or_junior in student) print "The club has", student[senior_or_junior], senior_or_junior, "students"}
BEGIN部分设置域分隔符为#,初始化两个数组的内容元素。然后处理文件,先给数组命名为colour,使用循环语句比对$1是否等于数组元素之一(Yellow、Orange或Red),如果匹配,依照匹配元素将运行总数保存进数组。同样的方法处理数组senior_or_junior。END部分打印浏览结果,对每一个数组使用循环语句并打印
收集awk的一些技巧方案
awk [opion] 'awk_script' input_file1 [input_file2 ...] awk的常用选项option有:
① -F fs : 使用fs作为输入记录的字段分隔符,如果省略该选项,wak使用环境变量IFS的值。
② -f filename : 从文件filename中读取awk_script。
③ -v var=value : 为awk_script设置变量。
1、删除重复的行 
#awk '!a[]++'

2、将数据文件中的每个词的第一个字母变成大写
dingyi@backup:~$ cat test
linux is long live!!!
i am a cuer

dingyi@backup:~$ awk ',1,1); sub(/^./,toupper(first),); print }' test
Linux is long live!!!
I am a cuer
awk 请教

下面是文件一,文件二
  $cat file1
00001       20
00002       31
00003       04
00004       56
00005       94
00006       73
00007       25
00008       86
00009       19
00010       52

$cat file2
00001       20
00007       28
00002       32
00004       56
00010       52

怎样的shell才能使file1、file2两个文件的$2不同的话,取出全局$0?
注意:比较两个文件的$2的时候,一定要第一列相同的情况下才比较

请大虾执教

li2002 2003-9-11 08:57
 
awk 请教

不就是找出不同行吗?
cat file1 file2|sort |uniq -u

deathcult 2003-9-11 09:15
 
awk 请教

paste file1 file2|awk '{if(($1==$3)&&($2!=$4))print$0}'

bjgirl 2003-9-11 09:38
 
awk 请教

[code]
#!/bin/ksh
sort -n file1>nf
sort -n file2>mf
paste nf mf|awk '$1=$3 {print}'|awk '$2!=$4 {print}'
rm nf mf
结果:
00002 31 00002 32
00004 04 00004 56
00007 56 00007 28
00010 94 00010 52
[/code]

killua 2003-9-11 10:05
 
awk 请教

回一楼,最近在学awk啦,而且你那样得到的数值是
00002 31
00002 32
00003 04
00005 94
00006 73
00007 25
00007 28
00008 86
00009 19
00010 52
00010 52
而我要的是
00002 31  32
00007 25  28


二楼的没有数值哦,而且应该是paste file1 file2|awk '{if ($1 == $3 && $2 != $4) print $0}'[/quote]


awk 请教

三楼的答案是错的,我要是结果是

[color=red]00002 31 32
00007 25 28
[/color]
把$1相同,而$2不同的列出来

admirer 2003-9-12 00:45
 
awk 请教

这不是一个简单的paste能解决的问题,而是一个以关键字连接的问题!
[code]sort file1 >f1;sort file2 >f2; join -j1 1 f1 f2|awk '$2 != $3'
00002 31 32
00007 25 28[/code]

killua 2003-9-12 03:30 


 
awk 请教

[quote][i]原帖由 "yoof"]join -j1 1 f1 f2  请版主解释[/quote 发表:[/i]

以第一个文件的第一个域为索引键,连接f1,f2两个文件

文件处理

1.有文件gz.txt(工资)

4367422926350133100 张三 1250.00

4367422926351220178 李四 1300.00

4367422926351220546 王二 0

苏五丙 1340.00

4367422926351220178 孙六月 1390.00

…… ……

要求:按账号19位、姓名8位、工资8位来排列,且如姓名不足8位在之后补足,工资不足8位则在工资之前补。同时要求去掉工资为0的名单,没有账号在前补19位空格,并输出工资总数加以核对,处理后应如下排列:

4367422926350133100张三 1250.00

4367422926351220178李四 1300.00

苏五丙 1340.00

4367422926351220178孙六月 1390.00

…… ……

awk程序:

#------------------------------------

#shgz1.sh

sblank=" "

awk '$nf!="0"' $1 > tmp.txt #删除工资为0的人数

awk '<

if($1!~/[0-9]/)<

printf("%-19.19s%-8.8s%8.2f\n","'"$kk"'",$1,$2)> #如果没有账号补上空格

else<

printf("%-19.19s%-8.8s%8.2f\n",$1,$2,$3)>

>' tmp.txt > $2

awk '$nf~/[0-9]/<

sum=sum+$nf

>

end<

system("rm tmp.txt")

printf("the sum is%16.2f!\n", sum) #输出工资总数

>' $2

在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
Flag=abcd
awk '{print '$Flag'}' 结果为abcd
awk '{print "$Flag"}' 结果为$Flag

如何删除匹配之间的内容但不包括匹配行

我有这样一个文件:
Query=4567879
    sequence jkaskdjgkjasgasa;jghsafgkas
    jfaklslgjdla;;gsdakl;gd

                                                                           score     E
PUT-ASD-WEETED-001
PUT-ASD-WEQER5-001789
>PUT-ASD-WEETED-001
SDAGDSDS
>PUT-ASD-WEQER5-001789
DSGTSDTEW
.....
......
......
是这样的,我想删除
从score     E
到以第一个以>开头的中间所有的行,但不包括score     E行和第一以>开头的行

sed '/score     E/,/^>/d' urfile
肯定是不行的,把score     E行和第一以>开头的行也删掉了?
该怎么写呢?
其中要处理的文件中含有多个score     E和第一以>开头的之间的行,均删掉。

awk -v p=1 '/score/{p=0}/>/{p=1}p' urfile

教程二

awk的调用方式

前面曾经说过,awk提供了适应多种需要的不同解决方案,它们是:

一、 awk命令行,你可以象使用普通UNIX命令一样使用awk,在命令行中你也可以使用awk程序设计语言,虽然awk支持多行的录入,但是录入长长的命令行并保证其正确无误却是一件令人头疼的事,因此,这种方法一般只用于解决简单的问题。当然,你也可以在shell script程序中引用awk命令行甚至awk程序脚本。

二、使用-f选项调用awk程序。awk允许将一段awk程序写入一个文本文件,然后在awk命令行中用-f选项调用并执行这段程序。具体的方法我们将在后面的awk语法中讲到。

三、利用命令解释器调用awk程序:利用UNIX支持的命令解释器功能,我们可以将一段awk程序写入文本文件,然后在它的第一行加上:
#!/bin/awk -f
并赋予这个文本文件以执行的权限。这样做之后,你就可以在命令行中用类似于下面这样的方式调用并执行这段awk程序了。

$awk脚本文本名 待处理文件

awk的语法:

与其它UNIX命令一样,awk拥有自己的语法:

awk [ -F re] [parameter...] ['prog'] [-f progfile][in_file...]

参数说明:

-F re:允许awk更改其字段分隔符。

parameter: 该参数帮助为不同的变量赋值。

'prog': awk的程序语句段。这个语句段必须用单拓号:'和'括起,以防被shell解释。这个程序语句段的标准形式为:

'pattern {action}'

其中pattern参数可以是egrep正则表达式中的任何一个,它可以使用语法/re/再加上一些样式匹配技巧构成。与sed类似,你也可以使用","分开两样式以选择某个范围。关于匹配的细节,你可以参考附录,如果仍不懂的话,找本UNIX书学学grep和sed(本人是在学习ed时掌握匹配技术的)。 action参数总是被大括号包围,它由一系统awk语句组成,各语句之间用";"分隔。awk解释它们,并在pattern给定的样式匹配的记录上执行其操作。与shell类似,你也可以使用“#”作为注释符,它使“#”到行尾的内容成为注释,在解释执行时,它们将被忽略。你可以省略pattern和 action之一,但不能两者同时省略,当省略pattern时没有样式匹配,表示对所有行(记录)均执行操作,省略action时执行缺省的操作——在标准输出上显示。

-f progfile:允许awk调用并执行progfile指定有程序文件。progfile是一个文本文件,他必须符合awk的语法。

in_file:awk的输入文件,awk允许对多个输入文件进行处理。值得注意的是awk不修改输入文件。如果未指定输入文件,awk将接受标准输入,并将结果显示在标准输出上。awk支持输入输出重定向。

awk的记录、字段与内置变量:

前面说过,awk处理的工作与数据库的处理方式有相同之处,其相同处之一就是awk支持对记录和字段的处理,其中对字段的处理是grep和sed不能实现的,这也是awk优于二者的原因之一。在awk中,缺省的情况下总是将文本文件中的一行视为一个记录,而将一行中的某一部分作为记录中的一个字段。为了操作这些不同的字段,awk借用shell的方法,用$1,$2,$3...这样的方式来顺序地表示行(记录)中的不同字段。特殊地,awk用$0表示整个行(记录)。不同的字段之间是用称作分隔符的字符分隔开的。系统默认的分隔符是空格。awk允许在命令行中用-F re的形式来改变这个分隔符。事实上,awk用一个内置的变量FS来记忆这个分隔符。awk中有好几个这样的内置变量,例如,记录分隔符变量RS、当前工作的记录数NR等等,本文后面的附表列出了全部的内置变量。这些内置的变量可以在awk程序中引用或修改,例如,你可以利用NR变量在模式匹配中指定工作范围,也可以通过修改记录分隔符RS让一个特殊字符而不是换行符作为记录的分隔符。

例:显示文本文件myfile中第七行到第十五行中以字符%分隔的第一字段,第三字段和第七字段:

awk -F % 'NR==7,NR==15 {printf $1 $3 $7}'

awk的内置函数

awk 之所以成为一种优秀的程序设计语言的原因之一是它吸收了某些优秀的程序设计语言(例如C)语言的许多优点。这些优点之一就是内置函数的使用,awk定义并支持了一系列的内置函数,由于这些函数的使用,使得awk提供的功能更为完善和强大,例如,awk使用了一系列的字符串处理内置函数(这些函数看起来与C 语言的字符串处理函数相似,其使用方式与C语言中的函数也相差无几),正是由于这些内置函数的使用,使awk处理字符串的功能更加强大。本文后面的附录中列有一般的awk所提供的内置函数,这些内置函数也许与你的awk版本有些出入,因此,在使用之前,最好参考一下你的系统中的联机帮助。

作为内置函数的一个例子,我们将在这里介绍awk的printf函数,这个函数使得awk与c语言的输出相一致。实际上,awk中有许多引用形式都是从C语言借用过来的。如果你熟悉C语言,你也许会记得其中的printf函数,它提供的强大格式输出功能曾经带我们许多的方便。幸运的是,我们在awk中又和它重逢了。awk中printf几乎与C语言中一模一样,如果你熟悉C语言的话,你完全可以照C语言的模式使用awk中的printf。因此在这里,我们只给出一个例子,如果你不熟悉的话,请随便找一本C语言的入门书翻翻。

例:显示文件myfile中的行号和第3字段:

$awk '{printf"%03d%s\n",NR,$1}' myfile

在命令行使用awk

按照顺序,我们应当讲解awk程序设计的内容了,但在讲解之前,我们将用一些例子来对前面的知识进行回顾,这些例子都是在命令行中使用的,由此我们可以知道在命令行中使用awk是多么的方便。这样做的原因一方面是为下面的内容作铺垫,另一方面是介绍一些解决简单问题的方法,我们完全没有必要用复杂的方法来解决简单的问题----既然awk提供了较为简单的方法的话。

例:显示文本文件mydoc匹配(含有)字符串"sun"的所有行。

$awk '/sun/{print}' mydoc

由于显示整个记录(全行)是awk的缺省动作,因此可以省略action项。

$awk '/sun/' mydoc

例:下面是一个较为复杂的匹配的示例:

$awk '/[Ss]un/,/[Mm]oon/ {print}' myfile

它将显示第一个匹配Sun或sun的行与第一个匹配Moon或moon的行之间的行,并显示到标准输出上。

例:下面的示例显示了内置变量和内置函数length()的使用:

$awk 'length($0)>80 {print NR}' myfile

该命令行将显示文本myfile中所有超过80个字符的行号,在这里,用$0表示整个记录(行),同时,内置变量NR不使用标志符'$'。

例:作为一个较为实际的例子,我们假设要对UNIX中的用户进行安全性检查,方法是考察/etc下的passwd文件,检查其中的passwd字段(第二字段)是否为"*",如不为"*",则表示该用户没有设置密码,显示出这些用户名(第一字段)。我们可以用如下语句实现:

#awk -F: '$2=="" {printf("%s no password!\n",$1' /etc/passwd

在这个示例中,passwd文件的字段分隔符是“:”,因此,必须用-F:来更改默认的字段分隔符,这个示例中也涉及到了内置函数printf的使用。

awk的变量

如同其它程序设计语言一样,awk允许在程序语言中设置变量,事实上,提供变量的功能是程序设计语言的其本要求,不提供变量的程序设计语言本人还从未见过。

awk 提供两种变量,一种是awk内置的变量,这前面我们已经讲过,需要着重指出的是,与后面提到的其它变量不同的是,在awk程序中引用内置变量不需要使用标志符"$"(回忆一下前面讲过的NR的使用)。awk提供的另一种变量是自定义变量。awk允许用户在awk程序语句中定义并调用自已的变量。当然这种变量不能与内置变量及其它awk保留字相同,在awk中引用自定义变量必须在它前面加上标志符"$"。与C语言不同的是,awk中不需要对变量进行初始化, awk根据其在awk中第一次出现的形式和上下文确定其具体的数据类型。当变量类型不确定时,awk默认其为字符串类型。这里有一个技巧:如果你要让你的 awk程序知道你所使用的变量的明确类型,你应当在在程序中给它赋初值。在后面的实例中,我们将用到这一技巧。

运算与判断:

作为一种程序设计语言所应具有的特点之一,awk支持多种运算,这些运算与C语言提供的几本相同:如+、-、*、/、%等等,同时,awk也支持C语言中类似++、--、+=、-=、=+、=-之类的功能,这给熟悉C语言的使用者编写awk程序带来了极大的方便。作为对运算功能的一种扩展,awk还提供了一系列内置的运算函数(如log、sqr、cos、sin等等)和一些用于对字符串进行操作(运算)的函数(如length、substr等等)。这些函数的引用大大的提高了awk的运算功能。

作为对条件转移指令的一部分,关系判断是每种程序设计语言都具备的功能,awk也不例外。 awk中允许进行多种测试,如常用的==(等于)、!=(不等于)、>(大于)、<(小于)、>=(大于等于)、>=(小于等于)等等,同时,作为样式匹配,还提供了~(匹配于)和!~(不匹配于)判断。

作为对测试的一种扩充,awk也支持用逻辑运算符:!(非)、&&(与)、||(或)和括号()进行多重判断,这大大增强了awk的功能。本文的附录中列出了awk所允许的运算、判断以及操作符的优先级。

awk的流程控制

流程控制语句是任何程序设计语言都不能缺少的部分。任何好的语言都有一些执行流程控制的语句。awk提供的完备的流程控制语句类似于C语言,这给我们编程带来了极大的方便。

1、BEGIN和END:

在awk 中两个特别的表达式,BEGIN和END,这两者都可用于pattern中(参考前面的awk语法),提供BEGIN和END的作用是给程序赋予初始状态和在程序结束之后执行一些扫尾的工作。任何在BEGIN之后列出的操作(在{}内)将在awk开始扫描输入之前执行,而END之后列出的操作将在扫描完全部的输入之后执行。因此,通常使用BEGIN来显示变量和预置(初始化)变量,使用END来输出最终结果。

例:累计销售文件xs中的销售金额(假设销售金额在记录的第三字段):

$awk
>'BEGIN { FS=":";print "统计销售金额";total=0}
>{print $3;total=total+$3;}
>END {printf "销售金额总计:%.2f",total}' sx
(注:>是shell提供的第二提示符,如要在shell程序awk语句和awk语言中换行,则需在行尾加反斜杠\)

在这里,BEGIN预置了内部变量FS(字段分隔符)和自定义变量total,同时在扫描之前显示出输出行头。而END则在扫描完成后打印出总合计。

2、流程控制语句
awk提供了完备的流程控制语句,其用法与C语言类似。下面我们一一加以说明:

2.1、if...else语句:

格式:
if(表达式)
语句1
else
语句2

格式中"语句1"可以是多个语句,如果你为了方便awk判断也方便你自已阅读,你最好将多个语句用{}括起来。awk分枝结构允许嵌套,其格式为:

if(表达式1)
{if(表达式2)
语句1
else
语句2
}
语句3
else {if(表达式3)
语句4
else
语句5
}
语句6

当然实际操作过程中你可能不会用到如此复杂的分枝结构,这里只是为了给出其样式罢了。

2.2、while语句

格式为:

while(表达式)
语句

2.3、do-while语句

格式为:

do
{
语句
}while(条件判断语句)

2.4、for语句

格式为:

for(初始表达式;终止条件;步长表达式)
{语句}

在awk 的 while、do-while和for语句中允许使用break,continue语句来控制流程走向,也允许使用exit这样的语句来退出。break 中断当前正在执行的循环并跳到循环外执行下一条语句。continue从当前位置跳到循环开始处执行。对于exit的执行有两种情况:当exit语句不在 END中时,任何操作中的exit命令表现得如同到了文件尾,所有模式或操作执行将停止,END模式中的操作被执行。而出现在END中的exit将导致程序终止。

例:为了

awk中的自定义函数

定义和调用用户自己的函数是几乎每个高级语言都具有的功能,awk也不例外,但原始的awk并不提供函数功能,只有在nawk或较新的awk版本中才可以增加函数。

函数的使用包含两部分:函数的定义与函数调用。其中函数定义又包括要执行的代码(函数本身)和从主程序代码传递到该函数的临时调用。

awk函数的定义方法如下:

function 函数名(参数表){
函数体
}

在gawk中允许将function省略为func,但其它版本的awk不允许。函数名必须是一个合法的标志符,参数表中可以不提供参数(但在调用函数时函数名后的一对括号仍然是不可缺少的),也可以提供一个或多个参数。与C语言相似,awk的参数也是通过值来传递的。

在awk 中调用函数比较简单,其方法与C语言相似,但awk比C语言更为灵活,它不执行参数有效性检查。换句话说,在你调用函数时,可以列出比函数预计(函数定义中规定)的多或少的参数,多余的参数会被awk所忽略,而不足的参数,awk将它们置为缺省值0或空字符串,具体置为何值,将取决于参数的使用方式。

awk函数有两种返回方式:隐式返回和显式返回。当awk执行到函数的结尾时,它自动地返回到调用程序,这是函数是隐式返回的。如果需要在结束之前退出函数,可以明确地使用返回语句提前退出。方法是在函数中使用形如:return 返回值 格式的语句。

例:下面的例子演示了函数的使用。在这个示例中,定义了一个名为print_header的函数,该函数调用了两个参数FileName和PageNum, FileName参数传给函数当前使用的文件名,PageNum参数是当前页的页号。这个函数的功能是打印(显示)出当前文件的文件名,和当前页的页号。完成这个功能后,这个函数将返回下一页的页号。

nawk
>'BEGIN{pageno=1;file=FILENAME
>pageno=print_header(file,pageno);#调用函数print_header
>printf("当前页页号是:%d\n",pageno);
>}

>#定义函数print_header
>function print_header(FileName,PageNum){
>printf("%s %d\n",FileName,PageNum); >PageNum++;return PageNUm;
>}
>}' myfile

执行这个程序将显示如下内容:

myfile 1
当前页页号是:2

awk高级输入输出

1.读取下一条记录:

awk的next语句导致awk读取下一个记录并完成模式匹配,然后立即执行相应的操作。通常它用匹配的模式执行操作中的代码。next导致这个记录的任何额外匹配模式被忽略。

2.简单地读取一条记录

awk 的 getline语句用于简单地读取一条记录。如果用户有一个数据记录类似两个物理记录,那么getline将尤其有用。它完成一般字段的分离(设置字段变量$0 FNR NF NR)。如果成功则返回1,失败则返回0(到达文件尾)。如果需简单地读取一个文件,则可以编写以下代码:

例:示例getline的使用

{while(getline==1)
{
#process the inputted fields
}
}

也可以使getline保存输入数据在一个字段中,而不是通过使用getline variable的形式处理一般字段。当使用这种方式时,NF被置成0,FNR和NR被增值。

用户也可以使用getline<"filename"方式从一个给定的文件中输入数据,而不是从命令行所列内容输入数据。此时,getline将完成一般字段分离(设置字段变量$0和NF)。如果文件不存在,返回-1,成功,返回1,返回0表示失败。用户可以从给定文件中读取数据到一个变量中,也可以用stdin(标准输入设备)或一个包含这个文件名的变量代替filename。值得注意的是当使用这种方式时不修改FNR和NR。

另一种使用getline语句的方法是从UNIX命令接受输入,例如下面的例子:

例:示例从UNIX命令接受输入

{while("who -u"|getline)
{
#process each line from the who command
}
}

当然,也可以使用如下形式:

"command" | getline variable

3.关闭文件:

awk中允许在程序中关闭一个输入或输出文件,方法是使用awk的close语句。

close("filename")

filename可以是getline打开的文件(也可以是stdin,包含文件名的变量或者getline使用的确切命令)。或一个输出文件(可以是stdout,包含文件名的变量或使用管道的确切命令)。

4.输出到一个文件:

awk中允许用如下方式将结果输出到一个文件:

printf("hello word!\n")>"datafile"

printf("hello word!\n")>>"datafile"

5.输出到一个命令

awk中允许用如下方式将结果输出到一个命令:

printf("hello word!\n")|"sort-t','"

awk与shell script混合编程

因为awk可以作为一个shell命令使用,因此awk能与shell批处理程序很好的融合在一起,这给实现awk与shell程序的混合编程提供了可能。实现混合编程的关键是awk与shell script之间的对话,换言之,就是awk与shell script之间的信息交流:awk从shell script中获取所需的信息(通常是变量的值)、在awk中执行shell命令行、shell script将命令执行的结果送给awk处理以及shell script读取awk的执行结果等等。

1.awk读取Shell script程序变量

在awk中我们可以通过“'$变量名'”的方式读取sell scrpit程序中的变量。

例:在下面的示例中,我们将读取sell scrpit程序中的变量Name,该变量存放的是文本myfile的撰写者,awk将打印出这个人名。

$cat writename
:
# @(#)
#
.
.
.
Name="张三" nawk 'BEGIN {name="'Name'";\ printf("\t%s\t撰写者%s\n",FILENAME,name");}\
{...}END{...}' myfile
.
.
.

2.将shell命令的执行结果送给awk处理

作为信息传送的一种方法,我们可以将一条shell命令的结果通过管道线(|)传递给awk处理:

例:示例awk处理shell命令的执行结果

$who -u | awk '{printf("%s正在执行%s\n",$2,$1)}'

该命令将打印出注册终端正在执行的程序名。

3.shell script程序读awk的执行结果

为了实现shell script程序读取awk执行的结果,我们可以采取一些特殊的方法,例如我们可以用变量名=`awk语句`的形式将awk执行的结果存放入一个 shell script变量。当然也可以用管道线的方法将awk执行结果传递给shell script程序处理。

例:作为传送消息的机制之一,UNIX提供了一个向其所有用户传送消息的命令wall(意思是write to all写给所有用户),该命令允许向所有工作中的用户(终端)发送消息。为此,我们可以通过一段shell批处理程序wall.shell来模拟这一程序(事实上比较老的版本中wall就是一段shell批处理程序:

$cat wall.shell
:
# @(#) wall.shell:发送消息给每个已注册终端
#
cat >/tmp/$$
#用户录入消息文本 who -u | awk '{print $2}' | while read tty
do
cat /tmp/$$>$tty
done

在这个程序里,awk接受who -u命令的执行结果,该命令打印出所有已注册终端的信息,其中第二个字段是已注册终端的设备名,因此用awk命令析出该设备名,然后用while read tty语句循环读出这些文件名到变量(shell script变量)tty中,作为信息传送的终结地址。

4.在awk中执行shell命令行----嵌入函数system()

system()是一个不适合字符或数字类型的嵌入函数,该函数的功能是处理作为参数传递给它的字符串。system对这个参数的处理就是将其作为命令处理,也就是说将其当作命令行一样加以执行。这使得用户在自己的awk程序需要时可以灵活地执行命令或脚本。

例:下面的程序将使用system嵌入函数打印用户编制好的报表文件,这个文件存放在名为myreport.txt的文件中。为简约起见,我们只列出了其END部分:

.
.
.
END {close("myreport.txt");system("lp myreport.txt");}

在这个示例中,我们首先使用close语句关闭了文件myreport.txt文件,然后使用system嵌入函数将myreport.txt送入打印机打印。

写到这里,我不得不跟朋友们说再见了,实在地说,这些内容仍然是awk的初步知识,电脑永远是前进的科学,awk也不例外,本篇所能做的只是在你前行的漫漫长途中铺平一段小小开端,剩下的路还得靠你自己去走。老实说,如果本文真能给你前行的路上带来些许的方便,那本人就知足了!

如对本篇有任何疑问,请E-mail To:Chizlong@yeah.net或到主页http://chizling.yeah.net中留言。


附录:

1.awk的常规表达式元字符

\ 换码序列
^ 在字符串的开头开始匹配
$ 在字符串的结尾开始匹配
. 与任何单个字符串匹配
[ABC] 与[]内的任一字符匹配
[A-Ca-c] 与A-C及a-c范围内的字符匹配(按字母表顺序)
[^ABC] 与除[]内的所有字符以外的任一字符匹配
Desk|Chair 与Desk和Chair中的任一个匹配
[ABC][DEF] 关联。与A、B、C中的任一字符匹配,且其后要跟D、E、F中的任一个字符。
* 与A、B或C中任一个出现0次或多次的字符相匹配
+ 与A、B或C中任何一个出现1次或多次的字符相匹配
? 与一个空串或A、B或C在任何一个字符相匹配
(Blue|Black)berry 合并常规表达式,与Blueberry或Blackberry相匹配

2.awk算术运算符

运算符 用途
------------------
x^y x的y次幂
x**y 同上
x%y 计算x/y的余数(求模)
x+y x加y
x-y x减y
x*y x乘y
x/y x除y
-y 负y(y的开关符号);也称一目减
++y y加1后使用y(前置加)
y++ 使用y值后加1(后缀加)
--y y减1后使用y(前置减)
y-- 使用后y减1(后缀减)
x=y 将y的值赋给x
x+=y 将x+y的值赋给x
x-=y 将x-y的值赋给x
x*=y 将x*y的值赋给x
x/=y 将x/y的值赋给x x%=y 将x%y的值赋给x
x^=y 将x^y的值赋给x
x**=y 将x**y的值赋给x

3.awk允许的测试:

操作符 含义

x==y x等于y
x!=y x不等于y
x>y x大于y
x>=y x大于或等于y
x<y x小于y
x<=y x小于或等于y?
x~re x匹配正则表达式re?
x!~re x不匹配正则表达式re?

4.awk的操作符(按优先级升序排列)

= 、+=、 -=、 *= 、/= 、 %=
||
&&
> >= < <= == != ~ !~
xy (字符串连结,'x''y'变成"xy")
+ -
* / %
++ --

5.awk内置变量(预定义变量)

说明:表中v项表示第一个支持变量的工具(下同):A=awk,N=nawk,P=POSIX awk,G=gawk

V 变量 含义 缺省值
--------------------------------------------------------
N ARGC 命令行参数个数
G ARGIND 当前被处理文件的ARGV标志符
N ARGV 命令行参数数组
G CONVFMT 数字转换格式 %.6g
P ENVIRON UNIX环境变量
N ERRNO UNIX系统错误消息
G FIELDWIDTHS 输入字段宽度的空白分隔字符串
A FILENAME 当前输入文件的名字
P FNR 当前记录数
A FS 输入字段分隔符 空格
G IGNORECASE 控制大小写敏感0(大小写敏感)
A NF 当前记录中的字段个数
A NR 已经读出的记录数
A OFMT 数字的输出格式 %.6g
A OFS 输出字段分隔符 空格
A orS 输出的记录分隔符 新行
A RS 输入的记录他隔符 新行
N RSTART 被匹配函数匹配的字符串首
N RLENGTH 被匹配函数匹配的字符串长度
N SUBSEP 下标分隔符 "\034"

6.awk的内置函数

V 函数 用途或返回值
------------------------------------------------
N gsub(reg,string,target) 每次常规表达式reg匹配时替换target中的string
N index(search,string) 返回string中search串的位置
A length(string) 求串string中的字符个数
N match(string,reg) 返回常规表达式reg匹配的string中的位置
N printf(format,variable) 格式化输出,按format提供的格式输出变量variable。
N split(string,store,delim) 根据分界符delim,分解string为store的数组元素
N sprintf(format,variable) 返回一个包含基于format的格式化数据,variables是要放到串中的数据
G strftime(format,timestamp) 返回一个基于format的日期或者时间串,timestmp是systime()函数返回的时间
N sub(reg,string,target) 第一次当常规表达式reg匹配,替换target串中的字符串
A substr(string,position,len) 返回一个以position开始len个字符的子串
P totower(string) 返回string中对应的小写字符
P toupper(string) 返回string中对应的大写字符
A atan(x,y) x的余切(弧度)
N cos(x) x的余弦(弧度)
A exp(x) e的x幂
A int(x) x的整数部分
A log(x) x的自然对数值
N rand() 0-1之间的随机数
N sin(x) x的正弦(弧度)
A sqrt(x) x的平方根
A srand(x) 初始化随机数发生器。如果忽略x,则使用system()
G system() 返回自1970年1月1日以来经过的时间(按秒计算) 

教程三,转载:http://blog.youkuaiyun.com/zg_hover/archive/2009/12/20/5044195.aspx

awk教程

awk的基本功能是对文件进行指定规则浏览和抽取信息。

基本格式:

(1) awk [-F 分隔域] 'command' input-file(s)

(2) 写入shell脚本中

(3) awk -f awk-script-file input-file(s)

注意:这里如果使用if等编程语句,要用{}括起来。

test

name    grade     score     id

hover    2        96        2003073

twq      3        91        2003074

zsm      4        92        2003075

hzm      5        95        2003076

bl       6        96        2003077

1,文本过滤处理:

(1) awk '{print $0}' test   #打印文件的全部内容

注意:这里awk使用函数print用来打印整个文件的内容。其中的$0就表示整个文件的内容。

(2) awk '{print $1}' test   #抽取文件test中的第一列

注意:如果awk没有使用-F指定分隔符号,默认的分隔符号是空格和TAB键。

#列出所有的用户名和登陆的shell名

awk -F : '{print $1,$6}' /etc/passwd

(3) awk -F : '$1=="root" {print $0}' /etc/passwd

指打印用户名为root的那一行

2,文本格式定制

(1)给输出信息加上表头

awk -F : 'BEGIN {print "name        shell\n--------------------------------"}

    {print $!"\t"$6}' /etc/passwd

(2)

awk -F : 'BEGIN {print "name        shell\n--------------------------------"}

    {print $!"\t"$6} END {"end-of-report"}' /etc/passwd

3,在awk中使用正则表达式

^                表示匹配行首的字符

[...]            匹配[]正的任意一个字符

(str1|str2)        匹配含有str1或str2的行       

.                匹配任意一个字符

(1)匹配

为使一域匹配一正则表达式,可以使用以下两种方法:

    1)$n~正则表达式

    2)if($n~正则表示式) print $0

awk -F: '$0 ~ /^root/' /etc/passwd  #打印以root开头的行

awk -F: '{if($0 ~ /^root/) print $0}' /etc/passwd  #和上一句等效

*精确匹配*

#打印名字为root的用户在/etc/passwd文件中的记录

awk -F : '$1=="root" {print $0}' /etc/passwd

#打印路径为/root的用户在/etc/passwd中的记录

awk -F : '$6=="\/root" {print $0}' /etc/passwd

4,在awk中使用条件操作符

<    小于        >=    大于等于

<=    小于等于    ~    匹配正则表达式

==    等于        !~    不匹配正则表达式

!=    不等于

(1)模糊匹配

i)使用if         {if($1~/zhengxh/) print $0}

ii)不用if        '$0 ~ /zhengxh/'

ex:

    awk '$0~/zhengxh/' filename

    或awk '{if($0~/zhengxh/) print $0} filename    #输出含有zhengxh的行

    或awk '/zhengxh/' filename

(2)精确匹配

$n=="chars"

    awk '$1=="zhengxh" {print $0}' filename        #输出第一列等于zhengxh的行

(3)反向匹配

$n !~ /adf/

    awk '$1 !~ /zhengxh/ {print $0}' filename    #输出第一列不是zhengxh的行

(4)大小写匹配

    awk '/[zZ]hengxh/'  filename     #匹配含有zhengxh 或是Zhengxh的字符串

   

(5)使用或运算

    awk '$0 ~ /(zhengxh|hover)/' filename     #查找含有zhengxh或hover字串的行

    或awk '{if($0~/zhengxh/ OR $0~/hover/) print $0}' filename

(6)内置变量

ARGC    命令行参数个数

ARGV    命令行参数排列

ENVIRON    环境变量支持队列的

FNR        浏览文件的记录数

FS        设置输入域分隔符,与-F同

NF        记录域的个数

NR        已读的记录数

OFS        输出域分隔符

ORS        输出记录分隔符

RS        控制记录分隔符

awk 的具体运用(FAQ)

* 把一个文件中满足条件的放到一个文件不满足条件的放到另一个文件

awk -F: '{if(NF==6) print $0 > "yes" else print $0 > "no" }' filename

*如何在awk中使用变量

要注意的是在awk中的表达式一般是用''号括起来的,在shell中单引号是全屏蔽符,所以用单引号使得变量无法生效,在使用shell变量时,可以这样使用

##########################

#/bin/sh

#

name="zhengxh"

count=`awk -F: '

    /'${name}'/{        #这里需要使用变量的地方把变量隔开

        sum+=$3   

    }

   

    END { print sum }

'`

*使用awk输出文件的倒数第N行

tail -n $N $filename | awk '{if(NR==1) print $0}'

*)如何在AWK中使用外部变量

1)aa="aaaaaaa"

awk '{print "'"${aa}"'"}' $filename

2)

以下使用外部变量时有错:

#!/bin/bash

filepath=/etc/passwd

user=root

result=`awk -F":" '/$user/ { print $1}' $filepath`

echo $result

$

改正:

awk -F':' '/'"$user"'/{print $1}' $filepath

*如何把AWK中的值,传送到外部的SHELL变量

使用$() 或 ``

aa=`awk -F: '{print $0}' $filename`

*进行统计

文件aa.txt

一个用户可能有多个记录,这时只统计一次:

数据          用户ID        下载文件名称   用户所在地  等。。。。。

20071128,0001,1,null,600571021800,028 

20071128,0002,1,null,600571001800,021

20071128,0002,1,null,600571001802,021

20071128,0003,1,null,600571031800,020

20071128,0004,1,null,600571001800,010

统计各个的号码(最后一个字段)数量

awk -F, '{if(!b[$2$6]){a[$6]++;b[$2$6]++}}END{for(i in a){print i,a[i]}}'

*如何把多个语句放在一句话(一行)中处理

cat "$file" | awk '{ip=$1; i=index($0,"\google"); if(i>1){ua = substr($0,i); print ip "\t" ua}}'

*把记录

aa,bb,cc [name, address, age]

变成记录

ip,aa,bb,cc [ip,name,address,age]

awk -F,    '{pirntf "\"192.168.5.154\","$0}'

*取一个字符串的首字母

str=abc

echo ${str:0:1}

echo $str|awk '{print substr($0,1,1)}'

echo $str|sed 's/\(.\).*/\1/'

*如何在一字符串的前面加上字符串 addtext

awk '{print "addtext \""$0"\""}' temp

*计算不重复的列的总和

aa|001|23

ac|001|23

bb|002|213

cc|004|32

dd|005|34

awk -F'|' '!a[$1]++{sum+=$3} END{print sum} ' filename

*定义多个分界符

aa cc dd

bb,ee ff

awk -F'[ ,]' '{print $3}' filename

有时候有可能出现多个分隔符号,但是我们需要把它当成一个,这时就要用:

***

#echo "adf::adf:f" | awk -F'[:]+' '{print $2}'

#adf

***

#echo "adf::adf:f" | awk -F':' '{print $2}'

#                            #输出空

***

*如何用awk处理这样的文件格式?

源文件格式:

  

表1313

                               客户经理业绩情况表(月报表)

支局所名称:XXXX储蓄所    月份:10     

客户经理

业绩(累计日积数)

酬金

姓名                  代号     活期               整整3月

整整6月               整整1年            整整2年                整整3年

整整5年             整整8年               零整1年             零整3年

零整5年              定活两便         

兰                  37040576  0.00                 0.00                 0.00

0.00                 0.00                 0.00                 0.00

0.00                 0.00                 0.00                 21340.00

0.00                 0.00                  

禚树征              37040585  27277.21             120.00               0.00

2965.22              0.00                 0.00                 0.00

0.00                 0.00                 0.00                 0.00

0.00                 845615151469035520.00

秦                  37040502  20094.30             0.00                 0.00

0.00                 0.00                 0.00                 0.00

0.00                 0.00                 0.00                 0.00

0.00                 622937933443235840.00

           合     计          444868.41            0.00                 0.00

2965.22              0.00                 0.00                 10764.20

0.00                 0.00                 0.00                 0.00

18600.00             13791245122257916000.00

如何用awk处理成以下格式(只要里面的记录并用逗号分割每个字段,最后一个字段不要,表头和表尾不要):

"兰",37040576,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,21340.00,0.00                 

"禚树征",37040585,27277.21,120.00,0.00,2965.22,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00

"秦",37040502,20094.30,0.00,0.00,0.00,0.00,0.00,,0.00,0.00,0.00,0.00,0.00,0.00

awk '{sub("[ \t]", ","); print $0}' temp

awk '{sub("[ ,\t]", ","); print $0}' temp

*如何用TAB做分隔符号

awk -F'\t'

awk -F'[ \t]'  #默认是这样,以空格或TAB做分隔符

一般模式:awk -F'rexp' '{}' filename

这里rexp是一个正则表达式,用来指示要使用的分隔符。

*--------------------------

在awk脚本中有下面一段

BEGIN{split("123#456#789",team,"#")}

END{for(i in team) print team}

预测的输出应该是

123

456

789

啊!

为什么实际的输出是

456

789

123

呢?

答:

---

while(++i in team) print team[i]

----------------------------

*-awk中使用system()

answer:

ls | awk '{if (system("ls " $0) == 0) {print "file " $0 " exists !"}}'

*-调用外部命令和awk结合

使用getline得到外部命令的输入f

 ls | awk '{getline ll; print $ll}'

--------------------------

*-只输出第一行的内容

awk '{print; exit}'

*-多shell命令

awk ’BEGIN{while("dir|sed 1,3!d"|getline)print $1}‘

*-在awk的输出中加单引号

#cat file

rwxrwsrwx   gprs    512 GPRS

awk '{printf("%s %s '"'%s'"' %s\n",$1,$2,$3,$4)}' file

    在这里要理解的是:上面的表达式分成了三块,前面的''内的内容是一块,中间的双引号内的内容是一块,最后的单引号里的内容是一块;由于单引号在双引号中的作用被屏蔽,所以输出的变量会

带上单引号。从而达到预定结果。

*-得到df -h 显示出来的百分数字(去掉百分号)

(1)df -h | awk '{if(NR!=1) print $5}' | cut -d% -f 1

(2)df -h | awk -F'[ \t%]+' '{if(NR!=1) print $5}'

***

实现加和

中间结果如下所示:

CPU usr sys idl

0 13 4 76

1 9 4 79

要想显示下列结果:

1 22 8 155

***

cat data | awk '{if(NR!=1) a+=$1;b+=$2;c+=$3} END{print a,b,c,d,e}'

***

如何实现以几个字母中任意一个打头的字符串的查找

cat data

Mike Harrington:(510) 548-1278:250:100:175

Christian Dobbins:(408) 538-2358:155:90:201

Susan Dalsass:(206) 654-6279:250:60:50

Archie McNichol:(206) 548-1348:250:100:175

Jody Savage:(206) 548-1278:15:188:150

Guy Quigley:(916) 343-6410:250:100:175

Dan Savage:(406) 298-7744:450:300:275

Nancy McNeil:(206) 548-1278:250:80:75

John Goldenrod:(916) 348-4278:250:100:175

Chet Main:(510) 548-5258:50:95:135

Tom Savage:(408) 926-3456:250:168:200

Elizabeth Stachelin:(916) 440-1763:175:75:300

awk -F'[ :]' '$1~/^[MJ] {print $1}'

输出以D开头的域

awk -F':' '{for(i=1;i<=NF;i++) if($i~/^D/) print $i}' data2

****每一行的和

统计

#cat ab

a 1

a 2

b 2

awk '{a[$1]+=$2} END{for(i in a) print i,a[i]}' file

-----------------------------------

*对两个文件的处理

----------

大家好,想请教一个问题,我现在有两个文件,如下所示,这两个文件格式都是一样的。我想首先把文件2的第五列删除,然后用文件2的第一列减去文件一的第一列,把所得的结果对应的贴到原来第五

列的位置,请问这个脚本该怎么编写?

file1

50.481  64.634  40.573  1.00  0.00

51.877  65.004  40.226  1.00  0.00

52.258  64.681  39.113  1.00  0.00

52.418  65.846  40.925  1.00  0.00

49.515  65.641  40.554  1.00  0.00

49.802  66.666  40.358  1.00  0.00

48.176  65.344  40.766  1.00  0.00

47.428  66.127  40.732  1.00  0.00

51.087  62.165  40.940  1.00  0.00

52.289  62.334  40.897  1.00  0.00

file2

48.420  62.001  41.252  1.00  0.00

45.555  61.598  41.361  1.00  0.00

45.815  61.402  40.325  1.00  0.00

44.873  60.641  42.111  1.00  0.00

44.617  59.688  41.648  1.00  0.00

44.500  60.911  43.433  1.00  0.00

43.691  59.887  44.228  1.00  0.00

43.980  58.629  43.859  1.00  0.00

42.372  60.069  44.032  1.00  0.00

43.914  59.977  45.551  1.00  0.00

--答--

awk 'NR==FNR{a[NR]=$1}NR!=FNR{$5=a[FNR]-$1;print}' file2 file1

说明:

当NR==FNR时,是第一个文件,到了第二个文件时FNR会从0开始计数,而NR却继续在原来的基础上自增。

先把第一个文件中要使用的内容保存到一个数组中,然后在处理第二个文件时才使用。

这里包含了很好的处理多个文件的方法,值得借鉴。

-------------------------------------------------

**

源文件如下:

37123456,123456789,601234020200051640,"孔霞","03",123456789,"2008/01/06",1,4000,5060.41

37123456,123456789,601234020200062521,"栗汝礼","03",123456010,"2008/01/06",1,100,110.91

37123456,123456789,601234020200069800,"柯纯龙","03",370786017,"2008/01/06",1,20000,19500

37123456,123456789,601234020200069800,"柯纯龙","03",123456030,"2008/01/06",1,31000,500

37123456,123456789,601234020200068018,"严凤书","03",123456789,"2008/01/06",2,50000,100163.39

37123456,123456789,601234020200070039,"刘庆","03",123456789,"2008/01/06",2,4000,8000

37123456,123456789,601234020200060554,"王兰英","03",123456789,"2008/01/06",1,1600,91.26

37123456,123456789,601234020200070039,"刘庆","03",123456789,"2008/01/06",2,4000,4000

37123456,123456789,601234020200067710,"罗有艳","03",123456789,"2008/01/06",2,3000,12012.01

37123456,123456789,601234020200064742,"孙祥婷","03",123456789,"2008/01/06",1,50,12.61

37123456,123456789,601234020200069800,"柯纯龙","03",123456030,"2008/01/06",1,200,300

37123456,123456789,601234020200060554,"王兰英","03",123456789,"2008/01/06",1,1000,1091.26

处理要求如下:

如果第三列中的数据是唯一的,就保留这一行,如果有重复的,就保留最后一个记录行。

--------答---------

awk -F, '{a[$3]=$0}END{for( i in a)print a[i]}' urfile

------------------------------

*如何快速获取特定字符串的前2(n)行和后2(n)行

$cat file

put 8

put 9

put 10

abc

put 11

put 12

put 13

put 14

abc

put 15

put 16

put 17

put 18

abc

put 19

put 20

put 21

put 22

put 23

abc

put 24

put 25

put 26

put 27

abc

put 28

put 29

put 30

put 31

put 32

abc

put 33

put 34

put 35

put 36

put 37

$ awk '{a[NR]=$0}/abc/{for(i=2;i>=0;i--) print a[NR-i];for(j=1;j<=2;j++){if(!getline) exit;print}print ""}' urfile

小结:

(1)这里使用了数组的功能,数组在作为缓存是普遍用法,要记住。

但这里如果文件超大的话,缓冲区的负担太大,应换存自己需要的哪些行(这里我只换存了4行)

$ awk '{a[NR%4]=$0}/abc/{for(i=2;i>=0;i--) print a[(NR-i)%4];for(j=1;j<=2;j++){if(!getline) exit;print}print ""}' urfile

(2)使用了getline函数-- $ man awk  就知道,getline函数的作用是: 1)读取下一行2)set $0

注意这两个元素的应用.

*)如何提取aaaa12123adsf adfadfbbbb 的aaaa和bbbb中间的内容

$cat file

adfaaaaadfadfadfdfadabbbb

adfaaaaadf  ad323452 adfadfdfadabbbbz

$

1)sed -e 's/.*\(aaaa\)\(.*\)\(bbbb\).*/\2/g' file

2)sed -e 's/.*\(a\{3\}\)\(.*\)\(b\{3\}\).*/\2/g' file

3)echo "aaaa121312dfadfbbbbb" | awk -F'aaaa|bbbb' '{print $2}'

*)我以如下字符要处理

a  123

b  124

c   125

a   126

d   127

e   128

ac  129

如果第一列出现两次或两次以上将其打印出来,并计算出现次数。

$ awk '{a[$1]++;} END{for(i in a) if(a[i]>=2) {print i,a[i]}}' file

分析: 由以上的命令可以得到流程:

a["a"] 2

a["b"] 1

a["c"] 1

a["d"] 1

a["e"] 1

a["ac"] 1

而for(i in a)  则是要遍历的i的值是:a,b,c,d,e,ac

*)去掉重复的行

awk '!a[$0]++' file

*)去掉重复行,并保持顺序不变

awk 'f[$0]!=1{print;f[$0]=1}'

*)打印重复行

1)awk '{a[$0]++} END{for(i in a) {if(a[i]>1){print i}}}' filename

2)sort cc  | uniq -dc

*)如何匹配多个模式

1)awk '/p1|p2/' file

2)awk '/zhengxh|\<root\>' file

*)设定字段分隔符

1)awk -F':' '{OFS="-"}{print $1,$2,$3}' file

*)范围查找

1)awk -F':' '/20080501[2-9]/' file

*)数字计算求和 file:

hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95

drills QTY: 2 PRICE: 29.99 TOTAL: 59.98

punches QTY: 7 PRICE: 3.59 TOTAL: 25.13

drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18

bits QTY: 55 PRICE: 1.19 TOTAL: 65.45

saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77

nails QTY: 800 PRICE: .19 TOTAL: 152

screws QTY: 80 PRICE: .29 TOTAL: 23.2

brads QTY: 100 PRICE: .24 TOTAL: 24

1)awk '{x=x+$2}' file

*)

---

3  0.022913642968727541

2   0.022706007307485104

2  0.50444767354650166

3   0.022128299612739447

6   0.025468440060252208

1  0.022856042968727539

第一列相同则第二列对应值求和。。。输出$1,sum

---

1)awk '{a[$1]=+$2; b["2"$1]++} END{for(i in a) if(b["2"i]>1) print i,a[i]}' file

*)我以如下字符要处理

a  123

b  124

c   125

a   126

d   127

e   128

ac  129

如果第一列出现 两次或两次以上 将其打印出来,并计算出现次数。

1)awk '{a[$1]++} END{for(i in a) print i,a[i]}' file

------

*)awk中如何显示大数据

1)awk  '{printf"%.f\n", NR + 1211439408282}'   filename

*)awk使用外部变量

1)awk '{if($3=="'$a'") print $1,$2,"'$b'",$4}' text

2)awk '{if($3=='\"$a\"') print $1,$2,'\"$b\"',$4}' text

*)

文件内容:

74683 1001

74683 1002

74683 1011

74684 1000

74684 1001

74684 1002

74685 1001

74685 1011

74686 1000

....

100085 1000

100085 1001

文件就两列,希望处理成

74683 1001 1002 1011

74684 1000 1001 1002

...

就是只要第一列数字相同, 就把他们的第二列放一行上,中间空格分开

--------------

1) awk '{a[$1]=sprintf("%s %s", a[$1],$2)} END{for(i in a) print i,a[i]}' file

2) awk '{a[$1]=a[$1]" "$2} END{for(i in a)print i,a[i]}' data13

*)

76523  1001 1002

76524  1002 1003

76526  1000 1003

76528  1000

....

100025  1000 1025

请教下, 文件第一列已按大小排序, 现在想按第一列的顺序, 把没有出现的行数补上

实现

76523  1001 1002

76524  1002 1003

76525

76526  1000 1003

76527

76528  1000

....

100025  1000 1025

怎样能够直接补上这些缺失的行

-------------------

1)???????

*)

每个字段形如 <data name="CYRSBH" value="320400725220211"/>,如何高效的提取value="*****"中间的*** 望各位不吝赐教

-------------

1) grep -o "value=.*\"" data7 | awk -F'"' '{print $2}'

2) sed 's/.*value="\(.*\)".*/\1/' file

*)

---

两个文件

a

b

#cat a

a1    b=1  num=3  c=2

a3   b=1   num=3  c=3

bc    f=3    num =2 f=3

fa     f=4    num=2  f=6

#cat b

a4    b=1   num=6 c=3

a1    b=1  num=5 c=2

bc    f=3    num =1 f=3

fb    f=4    num=3  f=6

要求对比两个文件

条件1:如果文件a中有和文件b第1,2,4部分都相同的行则用文件b中该行的第三部分num=x

其x的值减去文件a中该行第三部分num=x其x的值,并将结果连同该行的其他部分写入文件c

例如:

文件b中第二行a1    b=1  num=5 c=2的第一部分:a1

,第二部分b=1,第4部分c=2和文件a的第一行a1    b=1  num=3

c=2相应部分相同则将结果

a1    b=1  num=2 c=2    写入文件c

(num=2是文件b的num=5减去文件a的num=3的得来的)

条件2:如果条件1中num后数值相减后该结果为负值则将文件b中的该行直接写入文件c

例如:b中的第三行bc    f=3    num =1 f=3与文件a中的第三行bc    f=3    num =2

f=3的1,2,4部分相同,但是num后数值的运算结果为-1

(1减2得来的)所以直接将文件b中的该行bc    f=3    num =1 f=3直接计入文件c

条件3:如果文件a中没有找到和文件b中1,2,4部分相同的行则将文件b中的该行直接写入文件c

例如:文件b的第四行fb    f=4    num=3

f=6,在文件a中无法找到和他第1,2,4部分相同的行所以直接将该行写入文件写入文件c

条件4:a或者b本文本身中不会出现第1,2,4部分相同的行

---

test.awk

#!/bin/awk -f

NR==FNR {

        sub(/.*=/ ,"" ,$3)

        h[$1$2$4] = $3

}

NR>FNR {

        i = 0

        sub(/.*=/, "" ,$3)

        if($1$2$4 in h) {

                i = $3 - h[$1$2$4]

        }

        if(i>0) $3 = "num="i

        else $3 = "num="$3

        print

}

awk -f test.awk a b > c

*)awk对文件进行分流

$cat file:

00:49:42.025791        14058101005        2008-05-31 09:41:2

-00:00:34.974209        14058101003        2008-05-31 10:31:4

...

目的是把以00开头的行输出到一个文件,-00开头的行输出到一个文件,用一条awk语句可以实现么?

*)

如何在文件中使用awk设定的变量

参考: #awk -v min=43922 -v max=52059 '{a[$1]}END{for(i=min;i<=max;i++)if(!(i in a))print i}'

*)

3  0.022913642968727541

2   0.022706007307485104

2  0.50444767354650166

3   0.022128299612739447

6   0.025468440060252208

1  0.022856042968727539

。。。

第一列相同则第二列对应值求和。。。输出$1,sum

这样的是错误的!!!

#awk  'a[$1]+=$2; END{for(i in a) print i,a[i]}' cata3

right :

awk  '{a[$1]+=$2} END{for(i in a) print i,a[i]}' cata3

*)

有一个类似于这样的文本:

16  001agdcdafasd

16  002agdcxxxxxx

23  001adfadfahoh

23  001fsdadggggg

我想要得到

16  001

16  002

23  001

23  002

在awk中,就是取$2的前三个字符,但是不知道如何处理

大家帮帮忙哦,先谢谢了:)

----

1)awk '{print $1,substr($2,1,3)}'

2)sed 's/\(.* ...\).*/\1/' file

3)grep -o '^.\+ \+...' file

*)把文件 file

CHN0401

部门1组

分部门查询

吴斌

CHN0402

部门2组

查询

李演

CHN0403

部门3组

查询

李路

变为

-------------------------------------------

CHN0401 部门1组 分部门查询 吴斌

CHN0402 部门2组 查询 李演

CHN0403 部门3组 查询 李路

1)

awk '/CHN/{h=$1; sub("\n","",h); printf "%s ",h; for(i=0; i<=3; i++) {if(getline var) { sub("\n","",var);} var=sprintf("%s ", var); printf "%s",var; }print "";}' file

2)

$cat ff.awk 

#!/bin/awk -f

#

/CHN/{

    h=$1;

    sub("\n","",h);

    printf "%s ",h;

    for(i=0; i<=3; i++)

    {

        if(getline var)

        {

            sub("\n","",var);

        }

        var=sprintf("%s ", var);

        printf "%s",var;

    }

    print "";

} file

$ff.awk filename

#!/bin/awk -f

#

/CHN/{

    s=$0;

    for(i=0; i<=3; i++)

    {

        getline

        s=sprintf("%s %s", s,$0);

    }

    printf "%s", s;

    print "";

} file

*替换特定行之间的行

*) 替换注释行<!-- -->

<!-- <mapping

                        resource="0.xml" />-->

<mapping resource="1.xml" />

  <mapping resource="2.xml" />

<!-- <mapping

                        resource="3.xml" />

-->

  <mapping resource="4.xml" />

<!--

<mapping

                        resource="5.xml" />

-->

<!-- <mapping resource="6.xml" />-->

  <mapping resource="7.xml" />

1)awk 'BEGIN{RS="<!--|-->"}NR%2' urfile

*)使用多个单词作为分隔符

awk -F'word1|word2' '{print $3}'

*) 把不同的结果定向到不同的文件中去

有这样个文件

123|0|444

123|1.00|444

588|222|333

现在想把第2个字段为0的取出来输出到一个文件,并删除该记录,用awk如何实现,谢谢

代码如下:

-----------------------------------------------

[zhengxh@hoverzg stdshell]$ cat dd

123|0|444

123|1.00|444

588|222|333

#注意在输出的文件名前面要加双引号

[zhengxh@hoverzg stdshell]$ awk -F'|' '{if($2==0)print >"file1"; else print >"file2"}' dd

[zhengxh@hoverzg stdshell]$ cat file1

123|0|444

[zhengxh@hoverzg stdshell]$ cat file2

123|1.00|444

588|222|333

-----------------------------------------------

*)

比如解析下面一行:

123||name||address||age

我想以“||”为分割符,这样各个域为“123”, “name”,“age”

1)awk -F"[|]+" '{print $1}' filename

*)单引号的输出

1) awk 'BEGIN{print "'\'看我的\''";}'

*)找出不含指定字符串的行

awk '!(/abc/||/def/)

找出不含abc或者不含def的列作为条件

-----------------------------------------------

[zhengxh@hoverzg stdshell]$ awk '!(/dd/||/1/) {print }' dd

588||222||333

[zhengxh@hoverzg stdshell]$ cat dd

123||0||444

123||1.00||444

588||222||333

-----------------------------------------------

*)只处理最后一行

1)awk 'END{ print $0}' test

2)tail -1 | awk ...

*)只是处理第一行

1) awk '{print $0; exit}' filename

2) head -1 file | awk ...

*)处理文件中指定的n行

1) awk '{if(NR==n) print }'

2) head -n | tail -m | awk ...

*) 某个文本文件,当逐行读取时,当发现第一个字段是空格或空值时(cut -d'  '

-f1),就将所在行与上行合并。

1)awk '/^[^ \t]/{printf "\n"$0}; /^[ \t]/{printf $0}END{printf "\n"}' file

1*) awk 'BEGIN{getline;printf $0}/^[^ \t]/{printf "\n"$0};\

    /^[ \t]/{printf $0}END{printf "\n"}' urfile

#注意如果用print是不能实现的,因为print 会打印一个\n

解释:

    如果前面的字符不是空格就打印一个\n,再打印这一行,

    如果是就直接打印但不换行

2)sed ':a;N;/\n[[:blank:]]\+/{s/\n//;ba};P;D' 数据文件

解释:

:a  设置跳转标签

N 读入下一行

/\n[[:blank:]]\+/{s/\n//;ba}

如果下一行是以空白开头的话,就把换行符删除,

然后再读取下一行,直到读取到不是以空白开头的行

P; 打印第一个换行符之前的内容

D; 删除第一个换行符之前的内容,并重新开始循环

*)

有个文件格式如下:

aaa

bbb

ccc

yyyuu

jjjkkk

sss

aaa

ccc

。。。。

有重复的字符串,要求对每个不一样的字符串计数并按计数的降序排列输出。输出的文件就只有各个不一样的字符串而已。

sort b | uniq -c | sort

*)

$ cat file

    DAA=

    123413

    ZZASDF

    DAA=

    123413

    ZZASDF

    DAA=

    123413

    ZZASDF

$ awk 'BEGIN{RS="DAA="} {gsub(/[^\n]/,"9",$0); if(length($0)>0) printf "%s %s",RS,$0}' file

*)

-----------------------

各位大牛好:

     小的有这样两个文件,记录不同查询出来的次数。

文件一 a.txt,有两个字段,一个是次数,一个是pid,具体如下:

      2 CC214798313J90000000000

      1 CC214798119J90000006000

      1 CC214790518J90000001000

      1 CC214790518

      1 CC214788013J90000005000

      1 CC214788013

      1 CC214783814J90000003000

      1 CC214783814J90000002000

      1 CC214783814

      1 CC214778610

文件二,b.txt ,也有两个字段,一个是次数,一个是pid,具体如下:

      1 CC153301918J90000010000_765

      1 CC120143642J90000043000_765

      1 CC000024062J90033095000_765

      1 CC000001583J90000044000_765

      1 CC000001583J90000046000_768

      1 CC130012773J90000076000_765

      1 CC130012773J90000063000_765

      1 CC130012773J90000064000_765

      1 CC130012773J90000051000_765

      1 CC130012773J90000052000_765

      1 CC138037658J90000044000_538

这两个文件记录的pid是可能相同的,我想把这两个文件组成一个文件:

次数1 次数2 pid

2 0 CC214798313J90000000000

1 0 CC214798119J90000006000

也就是合并两个文件中的两个字段 ,组成三个字段的第三个文件。

请假兄弟姐妹们。谢谢

--

*在指定行插入一行

awk '1;NR==1{print "addadf"}' file

-----------------------------------------

*awk能实现对一个文件进行不同条件的匹配,然后按匹配的不同输出不同的文件吗??

比如这样的文件:

##a1a1a1a1

b1:

@c1c1c1c1c1

d1:

%e1e1e1e1

##a2a2a2

b2:

@c2c2c2c2

d2:

%e2e2e2e2

将满足#开头的记录输出的a文件,将@开头的记录输出的b文件,将%的文件输出到c文件

所有操作希望通过一个脚本文件实现

这样条件我都知道怎么去配置就是不知道怎么按条件的不同输出啊,awk脚本能实现,如果不能怎么去实现它呢。

希望大侠们指教呢

do:

awk 'BEGIN{FS="";a["#"]="a";a["@"]="b";a["%"]="c"}($1 in a){print > a[$1]".txt"}' urfile

awk 'BEGIN{FS="";a["#"]="a";a["@"]="b";a["%"]="c"}($1 in a){print > a[$1]".txt"}' urfile

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/zg_hover/archive/2009/12/20/5044195.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值