awk

Awk

我的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kv lines变map
head pic.log | awk -F'`' '{for(i=1;i<=NF;i++){split($i,a,"=");m[a[1]]=a[2];} print m["width"]}'


head -n 10000 global/users.text/2015/04/13/part-00000 | grep tag_0004=0004 | awk 'BEGIN{FS="`"}{for(i=1;i<=NF;i++){split($i,a,"=");if(a[1]=="tag_0004" || a[1]=="fr" || a[1] =="uid"){printf("%s\t", $i)};} print ""}'|grep iphone
head -n 10000 global/users.text/2015/04/13/part-00000 | awk 'BEGIN{FS="`"}{for(i=1;i<=NF;i++){split($i,a,"=");if( a[1]=="fr" || a[1] =="uid"){printf("%s\t", $i)};} print ""}'
cat part-* | awk 'BEGIN{FS="`";count=0}{for(i=1;i<=NF;i++){split($i,a,"=");if( a[1]=="lives" ){ if(a[2]*1>2){count+=1}}}}END{print count;}'
gawk 'BEGIN {FS="`"};{sub(/.*=/,"",$1);print $1}' a.txt

gawk 'BEGIN {FS="`"};{for(i=1;i<=NF;i++){sub(/.*=/,"",$i);} print $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}' a.txt

seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'

gawk '$1~/foo/ {print $0}' BBS-list

awk ‘BEGIN{getline d < “data.txt”; print d}’ data2.txt

cmd = "curl -s " url "|iconv -f gb2312 -t utf-8";
cmd | getline result;
close(cmd);
print(result);

print cmd > "/dev/stderr"

技巧

  • 字符乘以1就可以转换成数字了,然后就可以比较了

手册

常用变量

FS 输入分隔符
RS="\n"

FNR 当前记录数(单文件范围内)
NR 当前记录数

OFS 输出分隔符 默认是空格
ORS 输出换行符 默认是"\n" 

FILENAME

字段

    默认字段分隔符FS=whitespace
    $1表示第一个栏位
    $2表示第二个栏位 
    $NF表示最後一个栏位
    $0表示整个记录。 

gawk 'BEGIN {FS=","}; {print $2}'

  • print item1, item2, …

    OFS 输出分隔符 默认是空格
    ORS 输出换行符 默认是”\n”

    • printf
  • patterns

    • /regular expression/

    • expression

    • pat1,pat2 一对的 patterns 以逗号分开,指定记录的范围

    • exp ~ /regexp/

    • exp !~ /regexp/ 如果 exp 不符合 regexp,则结果为真。

字符串

数组

相当于map

1
2
3
4
awk 'NR!=1{a[$6]++;} END {for (i in a) print i ", " a[i];}' netstat.txt
awk 'BEGIN{info="it is a test";split(info,tA," ");for(k in tA){print k,tA[k];}}'
awk 'BEGIN{info="it is a test";tlen=split(info,tA," ");for(k=1;k<=tlen;k++){print k,tA[k];}}'
length(arr)

多维数组

awk的多维数组在本质上是一维数组,更确切一点,awk在存储上并不支持多维数组。awk提供了逻辑上模拟二维数组的访问方式。例 如,array[2,4] = 1这样的访问是允许的。awk使用一个特殊的字符串SUBSEP (\034)作为分割字段,在上面的例子中,关联数组array存储的键值实际上是2\0344。

类似一维数组的成员测试,多维数组可以使用 if ( (i,j) in array)这样的语法,但是下标必须放置在圆括号中。
类似一维数组的循环访问,多维数组使用 for ( item in array )这样的语法遍历数组。与一维数组不同的是,多维数组必须使用split()函数来访问单独的下标分量。split ( item, subscr, SUBSEP)

5.3 比较的算式当作Patterns

比较的 pattern 用来测试两个数字或字串的关系诸如大於、等於
、小於。下面列出一些比较的pattern:

x<y 如果 x 小於 y,则结果为真。
x<=y 如果 x 小於、等於 y,则结果为真。
x>y 如果 x 大於 y,则结果为真。
x>=y 如果 x 大於、等於 y,则结果为真。
x==y 如果 x 等於 y,则结果为真。
x!=y 如果 x 不等於 y,则结果为真。
xy 如果 x 符合 regular expression y,则结果为真。
(p25 of
x!
y 如果 x 不符合 regular expression y,则结果为真。

上面所提到的 x 与 y,如果二者皆是数字则视为数字之间的比较,
否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同
的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视
为长的字串比短的字串大。例如 “10” 比 “9” 小,”abc” 比 “abcd” 小。

5.4 使用布林运算的Patterns

一个布林(boolean) pattern 是使用布林运算”或”(‘||’),”及”
(‘&&’),”反”(‘!’)来组合其它的pattern。
例如:

gawk ‘/2400/ && /foo/‘ BBS-list
gawk ‘/2400/ || /foo/‘ BBS-list
gawk ‘! /foo/‘ BBS-list

第六章 算式(Expression)作为Actions的叙述

算式(Expression) 是gawk程式里面action的基本构成者。

6.1 算术运算

gawk 里的算术运算如下所示:

x+y 加
x-y 减
-x 负
+x 正。实际上没有任何影响。
x*y 乘
x/y 除
x%y 求馀数。例如 5%3=2。
x^y
x**y x 的 y 次方。例如2^3=8。

6.2 比较算式与布林算式

比较算式 (comparison expression) 用来比较字串或数字的关系
,运算符号与 C 语言相同。表列如下:

x<y
x<=y
x>y
x>=y
x==y
x!=y
xy
x!
y

比较的结果为真(true)则其值是 1。否则其值是 0。
布林算式(boolean expression)有下面三种:

boolean1 && boolean2
boolean1 || boolean2
! boolean

6.3 条件算式(Conditional Expressions)

一个条件式算式是一种特别的算式,它含有3个运算元。
条件式算式与C语言的相同:

selector ? if-true-exp : if-false-exp

它有3个子算式。第一个子算式selector 首先会被计算。如果是真,
则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-
exp 会被计算且它的值变成整个算式的值。

例如下面的例子会产生x的绝对值:
x>0 ? x : -x

第七章 Actions里面的控制叙述

在 gawk 程式里面,控制叙述诸如 if、while 等控制程式执行的流
程。在 gawk 里的控制叙述与 C 的类似。

很多的控制叙述会包括其它的叙述,被包括的叙述称为 body。假
如 body 里面包括一个以上的叙述,必须以大括弧 { } 将这些叙述括起
来,而各个叙述之间需以换行(newline)或分号隔开。

7.1 if 叙述

if (condition) then-body [else else-body]
(p30 of
如果 condition 为真(true),则执行 then-body,否则执行 else-body。

举一个例子如下:

if (x % 2 == 0)
print “x is even”
else
print “x is odd”

7.2 while 叙述

while (condition)
body

while 叙述做的第一件事就是测试 condition。假如 condition 为真则
执行 body 的叙述。body 的叙述执行完後,会再测试 condition,假如
condition 为真,则 body 会再度被执行。这个过程会一直被重复直到
condition 不再是真。如果 condition 第一次测试就是伪(false),则
body 从没有被执行。

下面的例子会印出每个输入记录(record)的前三个栏位。

gawk ‘{ i=1
while (i <= 3) {
print $i
i++
}
}’

7.3 do-while 叙述

do
body
while (condition)

这个 do loop 执行 body 一次,然後只要 condition 是真则会重复执行 body。
(p32 of
即使开始时 condition 是伪,body 也会被执行一次。

下面的例子会印出每个输入记录十次。

gawk ‘{ i= 1
do {
print $0
i++
} while (i <= 10)
}’

7.4 for 叙述

for (initialization; condition; increment)
body

此叙述开始时会执行initialization,然後只要 condition是真,它
会重复执行body与做increment 。

下面的例子会印出每个输入记录的前三个栏位。

gawk ‘{ for (i=1; i<=3; i++)
print $i
}’

7.5 break 叙述

break 叙述会跳出包含它的 for、while、do-while 回圈的最内层。

下面的例子会找出任何整数的最小除数,它也会判断是否为质数。

gawk ‘# find smallest divisor of num
{ num=$1
for (div=2; div*div <=num; div++)
if (num % div == 0)
break
if (num % div == 0)
printf “Smallest divisor of %d is %d\n”, num, div
else
printf “%d is prime\n”, num }’

7.6 continue 叙述
(p34 of 46)
continue 叙述使用於 for、while、do-while 回圈内部,它会跳
过回圈 body 的剩馀部分,使得它立刻进行下一次回圈的执行。

下面的例子会印出 0 至 20 的全部数字,但是 5 并不会被印出。

gawk ‘BEGIN {
for (x=0; x<=20; x++) {
if (x==5)
continue
printf (“%d”,x)
}
print “”
}’

7.7 next 叙述、next file 叙述、exit 叙述

next 叙述强迫 gawk 立刻停止处理目前的记录(record)而继续下一
个记录。

next file 叙述类似 next。然而,它强迫 gawk 立刻停止处理目前
的资料档。

exit 叙述会使得 gawk 程式停止执行而跳出。然而,如果 END 出现
,它会去执行 END 的 actions。

内建函式(Built-in Functions)

内建函式是 gawk 内建的函式,可在 gawk 程式的任何地方呼叫内建
函式。

数值方面的内建函式

* int(x):int(3.9)=3,int(-3.9)=-3。 
* log(x)
* rand():数值平均分布在 (0,1)

字串方面的内建函式

* index(in, find) 在in中find第一次出现的地方,基于1,0找不到
* length(string) 
* match(string,regexp) 在string中寻找符合regexp的最长、最靠 

左边的子字串。传回值是 regexp 在 string 的开始位置,即 index
值。 同时,会设定内在变数 RSTART 等於 index,它也会设定内在变
数 RLENGTH 等於符合的字元个数。如果不符合,则会设定 RSTART 为
0、RLENGTH 为 -1。
* sprintf(format,expression1,…) 打印到字符串
* sub(regexp, replacement,target)

1
2
3
4
str = "water, water, everywhere" 
sub(/at/, "ith", str)
结果字串str会变成
"wither, water, everywhere"

* gsub(regexp, replacement, target)
1
2
3
4
str="water, water, everywhere" 
gsub(/at/, "ith",str)
结果字串str会变成
'wither, wither, everywhere"

* substr(string, start, length)
1
2
3
4
substr("washington",5,3) 
传回值为"ing"
substr("washington",5)
传回值为"ington"

* tolower(string)
* toupper(string)

输入输出的内建函式

close(filename)
将输入或输出的档案 filename 关闭。

system(command)
此函式允许使用者执行作业系统的指令,执行完毕後将回到 gawk
程式。
例如:
BEGIN {system(“ls”)}

第九章 使用者定义的函式(User-defined Functions)

复杂的 gawk 程式常常可以使用自己定义的函式来简化。呼叫使用
者定义的函式与呼叫内建函式的方法一样。

9.1 函式定义的格式

函式的定义可以放在 gawk 程式的任何地方。

一个使用者定义的函式其格式如下:

function name (parameter-list) {
body-of-function
}

name 是所定义的函式之名称。一个正确的函式名称可包括一序列的字
母、数字、下标线 (underscores),但是不可用数字做开头。

parameter-list 是列出函式的全部引数(argument),各个引数之
间以逗点隔开。

body-of-function 包含 gawk 的叙述 (statement)。它是函式定义
里最重要的部份,它决定函式实际要做何种事。

9.2 函式定义的例子

下面这个例子,会将每个记录的第一个栏位之值的平方与第二个
栏位之值的平方加起来。

{print “sum =”,SquareSum($1,$2)}
function SquareSum(x,y) {
sum=xx+yy
return sum
}

第十章 □例

这里将列出 gawk 程式的一些例子。

gawk ‘{if (NF > max) max = NF}
END {print max}’
此程式会印出所有输入行之中,栏位的最大个数。

gawk ‘length($0) > 80’
此程式会印出一行超过 80 个字元的每一行。此处只有 pattern 被
列出,action 是采用内定的 print。

gawk ‘NF > 0’
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
单的方法,将一个档案里的所有空白行删除。

gawk ‘{if (NF > 0) print}’
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
单的方法,将一个档案里的所有空白行删除。

gawk ‘BEGIN {for (i = 1; i <= 7; i++)
print int(101 * rand())}’
此程式会印出□围是 0 到 100 之间的 7 个乱数值。

ls -l files | gawk ‘{x += $4}; END {print “total bytes: “ x}’
此程式会印出所有指定的档案之bytes数目的总和。

expand file | gawk ‘{if (x < length()) x = length()}
END {print “maximum line length is “ x}’
此程式会将指定档案里最长一行的长度印出。expand 会将 tab 改
成 space,所以是用实际的右边界来做长度的比较。

gawk ‘BEGIN {FS = “:”}
{print $1 | “sort”}’ /etc/passwd
此程式会将所有使用者的login名称,依照字母的顺序印出

gawk ‘{nlines++}
END {print nlines}’
此程式会将一个档案的总行数印出。

gawk ‘END {print NR}’
此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk
来做。

gawk ‘{print NR,$0}’
此程式印出档案的内容时,会在每行的最前面印出行号,它的功
能与 ‘cat -n’ 类似。

第十一章 结论

gawk 对於资料的处理具有很强的功能。它能够以很短的程式完成
想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
工作,以 gawk 程式来写会比用其它程式语言来写短很多。
gawk 是 GNU 所做的 awk,它是公众软体(Public Domain) 可免费使
用。


awk ‘{printf(“%s “,$0);}END{print}’ test.txt 把多行转为一行,换行转空格。读入一行打印一行,但是不打印换行符,最后一行多打印一个换行符

多文件操作

awk进行多文件处理时候,常常会遇到2个方面问题,第一个是怎么样合并多个文件为一个文件。第二个问题就是怎么样将多行合并为一行显示。

1
2
3
awk 'FNR==1{print "\r\n"FILENAME}{print $0}' a.txt b.txt

cat a.txt b.txt | sort -n -k1 |awk 'NR%2==1{fd1=$2"\t"$3;next}{print $0"\t"fd1}'

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

💰

×

Help us with donation