由买买提看人间百态

boards

本页内容为未名空间相应帖子的节选和存档,一周内的贴子最多显示50字,超过一周显示500字 访问原贴
Linux版 - awk
相关主题
Grep 能作这个吗?求助文件切割问题
how to print in matrix using AWK?在emacs中怎么按照某种格式进行替换?
C++ 初级再初级问题 (转载)sed里面正则表达式匹配字符越少越好怎么写?
这本书比较好玩shell script question
segmentation fault as soon as entering 1 function in the ar (转载)install matlab
问一下C语言编CGI的路径问题 (转载)linux tcsh下less的问题
a sed questionhow do I remove this file???
请问怎么把两个行数相等的文件合并起来?dd-wrt 挂移动硬盘中文乱码的问题
相关话题的讨论汇总
话题: awk话题: print话题: 输出话题: 输入话题: 变量
进入Linux版参与讨论
1 (共1页)
g****g
发帖数: 1828
1
AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎
之一。这种编程及数据操作语言(其名称得自于它的创始人 阿尔佛雷德·艾侯 、
Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所
拥有的知识。 AWK 提供了极其强大的功能:可以进行正则表达式的匹配,样式装入、
流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语
言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言: AWK 程序设计语
言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程
序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,
还有无数其他的功能。gawk 是 AWK 的 GNU 版本。
最简单地说,AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 Unix
shell 编程语言,尽管 AWK 具有完全属于其本身的语法。它的设计思想来源于
SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工具 yacc 和 lex ,当然还
从 C 语言中获取了一些优秀的思想。在最初创造 AWK 时,其目的是用于文本处理,并
且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具
扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,
则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。
目录
[隐藏]
* 1 AWK程序结构
* 2 AWK命令
o 2.1 print 命令
o 2.2 内建变量
o 2.3 变量和语法
o 2.4 用户定义函数
* 3 样例程序
o 3.1 Hello World
o 3.2 输出长度大于80的行
o 3.3 输出单词计数
o 3.4 计算最后一个单词的和
o 3.5 匹配输入行中的范围
o 3.6 计算词频
o 3.7 从命令匹配模式
* 4 自包含的AWK脚本
* 5 参见
* 6 外部链接
[编辑] AWK程序结构
AWK是一种处理文本文件的语言。它将文件作为记录序列处理。在一般情况下,文
件内容的每行都是一个记录。每行内容都会被分割成一系列的域,因此,我们可以认为
一行的第一个词为第一个域,第二个词为第二个,以此类推。AWK程序是由一些处理特
定模式的语句块构成的。AWK一次可以读取一个输入行。对每个输入行,AWK解释器会判
断它是否符合程序中出现的各个模式,并执行符合的模式所对应的动作。
—Alfred V. Aho, The A-Z of Programming Languages: AWK
AWK程序是由一系列模式--动作对组成的,写做
condition { action }
其中pattern表示AWK在数据中查找的内容,而action 是在找到匹配内容时所执行的一
系列命令。输入行被分成了一些记录:记录默认由换行符分割,因此输入会按照行进行
分割。程序使用给定的条件一个个的测试每条记录,并执行测试通过的条件所对应的
action。conditon和 action都可以省略不写。condtion默认匹配全部的记录;而默认
的 action则是打印原始记录。简单的AWK表达式之外,condition 可以是BEGIN 或END
;这两种条件对应的action 分别是读取所有的记录之前和之后。同时,如pattern1,
pattern2 的条件表示符合条件pattern1和pattern2 的记录及其之间的部分。 除了一
般的,C语言风格的算术和逻辑运算符外,AWK允许运算符~,用来测试正则表达式是否
可以与一字符串匹配。作为语法糖,没有~ 运算符的正则表达式会被用来对当前记录进
行测试,相当于/regexp/ ~ $0 。
[编辑] AWK命令
AWK命令即为前文例子中以action指代的语句。AWK命令可以包括函数调用,变量赋值,
计算,及/或各项的组合。标准AWK提供了许多内建函数;其部分实现则可能提供了更多
的内建函数。同时,AWK的部分实现支持动态连接库,使得其可以支持更多的函数。 便
利起见,下述例子中可能省略大括号({ } )。
[编辑] print 命令
print 命令用于输出文本。其输出的文本总是以"输出记录分隔符"(Output recode
separator, ORS)分割的,其默认值为换行符。该命令的最简形式为:
print
会输出当前记录的内容。在AWK中,记录会被分割成“域”,它们可以被分别显示
或使用:
print $1
显示当前记录的第1个域
print $1, $3显示当前记录的第1和第3个域,并以预定义的输出域分隔符(Output
field separator, OFS)分隔,其默认值为一个空格符
虽然域的符号($X ) 可能类似于某些语言中的变量(例如PHP和perl),但在AWK中,它们
指代的是当前记录的域。另外,$0 是指整个记录。事实上,命令print和print $0的效
果是相同的。 print命令也可以显示变量、计算、函数调用的结果:
print 3+2
print foobar(3)
print foobar(variable)
print sin(3-2)
其输出可以重定向到文件:
print "expression" > "file name"
或重定向到管道:
print "expression" | "command"
[编辑] 内建变量
AWK的内建变量包括域变量,例如$1, $2, $3,以及$0。这些变量给出了记录中域的内
容。 内建变量也包括一些其他变量:
* NR: 已输入记录的条数。
* NF: 当前记录中域的个数。记录中最后一个域可以以$NF的方式引用。
* FILENAME: 当前输入文件的文件名。
* FS: “域分隔符”,用于将输入记录分割成域。其默认值为“空白字符”,即空
格和制表符。FS可以替换为其它字符,从而改变域分隔符。
* RS: 当前的“记录分隔符”。默认状态下,输入的每行都被作为一个记录,因此
默认记录分隔符是换行符。
* OFS: “输出域分隔符”,即分隔print命令的参数的符号。其默认值为空格。
* ORS: “输出记录分隔符”,即每个print命令之间的符号。其默认值为换行符。
* OFMT: “输出数字格式”(Format for numeric output),其默认值为"%.6g"。
[编辑] 变量和语法
变量名可以是语言关键字外的,只包含大小写拉丁字母,数字和下划线(“_”)的任意
字。而操作符“+ - * /”则分别代表加,减,乘,除。简单的将两个变量(或字符串常
量)放在一起,则会将二者串接为一个字符串。若二者间至少有一个是常量,则中间可
以不加空格;但若二者均为变量,中间必须包括空格。字符串常量是以双引号(“"”)
分隔的。语句无需以分号结尾。另外,注释是以“#”开头的。
[编辑] 用户定义函数
函数是以与C语言类似的方式定义的,以关键字function开头,后面跟函数名称,参数
列表和函数体。
# 示例函数
function add_three (number) {
return number + 3
}
上面的函数可以如此调用:
print add_three(36) # 输出 39
函数可以拥有其私有变量。其私有变量可以写在参数列表之后,因为这些值会在调用函
数时被忽略。通常可以在参数列表中参数和私有变量之间加入一些空格,用以区别“真
正的”参数和私有变量。 函数声明中,函数名和括号间可以有任意空格,但在调用时
二者必须紧邻。
[编辑] 样例程序
[编辑] Hello World
AWK的hello world程序为:
BEGIN { print "Hello, world!" }
注意此处无需写出exit语句,因为唯一的模式是BEGIN。
[编辑] 输出长度大于80的行
输出长度大于80字符的行。注意模式的默认行为是输出当前行。
length($0) > 80
[编辑] 输出单词计数
对输入中的单词进行计数,然后输出行数,单词数和字符数(类似 wc)。
{
w += NF
c += length + 1
}
END { print NR, w, c }
由于没有提供模式,输入的全部行都可以匹配该模式,因此对每行都会执行预定操作。
注意w+=NF的含义等同于w = w + NF。
[编辑] 计算最后一个单词的和
{ s += $NF }
END { print s + 0 }
s是数值$NF的累加,而$NF则是每条记录中的最后一个域。NF是当前行中域的数量,例
如,4。由于$4是第4个域的值,$NF,在这种情况下等于$4,则当然是最后一个域的内
容。事实上,$是一个具有最高优先级的一元运算符。(若一行没有域,则有NF为0,而$
0是整行: 在这种情况下,要么是空串,要么只有空白符,因此其数值为0。)
文件结束时,END模式得到了匹配,因此可以输出s。然而,由于可能没有输入行,此时
s会没有值,从而导致没有输出。因此,对其加0可以使AWK在这种情况下对其赋值,从
而得到一个数值。这种方法是将字符串强制转化为数值的惯用法(反之,与空串连接则
是将数值强制转换为字符串的方法,例如s "")。如此处理之后,若程序输入为空文件
,可以得到“0”作为输出,而不是一个空行。
[编辑] 匹配输入行中的范围
$ yes Wikipedia | awk 'NR % 4 == 1, NR % 4 == 3 { printf "%6d %s\n", NR, $0
}' | sed 7q
1 Wikipedia
2 Wikipedia
3 Wikipedia
5 Wikipedia
6 Wikipedia
7 Wikipedia
9 Wikipedia
$
yes命令重复输入其参数(默认则是输出“y”)。在这里,我们让该命令输出“
Wikipedia”。动作块则输出带行号的内容。printf函数可以模拟标准C中的[[printf]]
函数,其效果与前述的print函数类似。而符合模式的行是这样产生的: NR是记录的编
号,也就是AWK正在处理行的行号(从1开始)。“%”是取余数操作符。因此,NR % 4 ==
1对第1,5,9等行为真。类似的,NR % 4 == 3对3,7,11等行为真。范围模式在其第
一部分匹配(例如对第1行)之前为假,并在第二部分匹配(例如第3行)之前为真。然后,
再在第二次匹配上其第一部分(例如第5行)前为假。sed命令则是用于截取其前7行输出
,防止yes命令一直运行下去。若head命令可用的话 ,这行命令的效果和head -n7相同
。 若范围模式的第一部分永远为真,例如设定为“1”,可以用来使该范围从输入的最
开始开始。类似的,若第二部分总是为假,例如“0”,则该范围的结束即为输入的结
束。 命令
/^--cut here--$/, 0
会输出从符合正则表达式“^--cut here--$”开始的输入行,也即从只包含“--cut
here--”的行开始,直到输入的结束。
[编辑] 计算词频
使用关联数组计算词频:
BEGIN {
FS="[^a-zA-Z]+"
}
{
for (i=1; i<=NF; i++)
words[tolower($i)]++
}
END {
for (i in words)
print i, words[i]
}
BEGIN块设定域分隔符为任意非字母字符。值得注意的是,分隔符不仅可以是字符串,
也可以是正则表达式。然后,程序对每个输入行执行相同的操作。在此,对每个域,我
们累加其小写形式出现的次数。最后,在END块中,我们输出单词及其出现的次数。代码
for (i in words)
建立了一个遍历关联数组中元素的循环,其中,i会被设为对应的键。这一点和多数语
言不同,而和Objective-C 2.0中的for...in语法相似。这样的语法允许以简单的方式
遍历数组,从而输出这些单词。另外,tolower函数是One True awk(见下文)的附加函
数。
[编辑] 从命令匹配模式
这个程序可以以多种不同形式出现。第一个使用Bourne shell脚本来完成大部分工作。
这也是最短的一个方法:
$ cat grepinawk
pattern=$1
shift
awk '/'$pattern'/ { print FILENAME ":" $0 }' $*
$
awk命令中的$pattern并没有为引号所保护。在这里,模式可以检查输入行($0)是否与
之匹配。FILENAME变量则包含了当前的文件名。awk没有显式的字符串连接操作符;与
BASH相似,只需简单的将字符串并列即可。$0则会输出原始的输入行。 也有另外的方
法来完成同样的任务。下面的脚本直接在awk中访问环境变量。
$ cat grepinawk
pattern=$1
shift
awk '$0 ~ ENVIRON["pattern"] { print FILENAME ":" $0 }' $*
$
这个脚本用到了数组ENVIRON,一个One True awk中引入的量。其作用类似与POSIX标准
中的getenv(3)函数。这个脚本先建立了一个名为pattern的环境变量,其值为脚本的第
一个参数,然后让awk在其余的参数所代表的文件内寻找该模式。 ~是用于检查其两个
操作数是否匹配的运算符;其逆则为!~。注意正则表达式也属于普通的字符串,可以储
存于变量中。 下面的方法则采用了在命令行对变量赋值的方法,即在awk的参数中写入
一个变量的值:
$ cat grepinawk
pattern=$1
shift
awk '$0 ~ pattern { print FILENAME ":" $0 }' "pattern=$pattern" $*
$
最后,这种方法是纯awk的,无需shell的帮助,也无需知道太多关于awk脚本实现的细
节(而在命令行对变量赋值的方法可能与awk的实现相关);但这种方法的脚本有点长:
BEGIN {
pattern = ARGV[1]
for (i = 1; i < ARGC; i++) # 去除第一个参数
ARGV[i] = ARGV[i + 1]
ARGC—if (ARGC == 1) { # 模式是唯一参数,因此强制从标准输入读取
ARGC = 2
ARGV[1] = "-"
}
}
$0 ~ pattern { print FILENAME ":" $0 }
BEGIN块的作用不仅仅是提取出第一个参数,也防止第一个参数在BEGIN块结束后直接被
解释为输入文件。ARGC,输入参数的数量永远是不小于1的,因为ARGV[0]是执行脚本的
命令名,通常是"awk"。另外,ARGV[ARGC]永远是空串。对于其中的if块,它表明若没
有指定输入文件,awk会直接读取标准输入流(stdin)。也即
awk 'prog'
也可以工作,因为程序中已经将ARGC置为了2;若该值为1,则awk会认为没有文件需要
读取而直接退出。同时,若需从标准输入读取数据,需要将文件名显式的指定为-。
[编辑] 自包含的AWK脚本
与许多其他的程序语言相似,可以利用“shebang”语法构建自包含的awk脚本。 例如
,一个名为hello.awk,可以输出“Hello, world!”的UNIX命令可以通过建立内容如下
,名为hello.awk的文件来完成:
#!/usr/bin/awk -f
BEGIN { print "Hello, world!" }
-f参数告诉awk将该文件作为awk的程序文件,然后即可运行该程序。
[编辑]
S*A
发帖数: 7142
2
FT, 现在还有谁用 awk 啊。
大家不是都用 Python, Perl 什么的么?

Unix

【在 g****g 的大作中提到】
: AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎
: 之一。这种编程及数据操作语言(其名称得自于它的创始人 阿尔佛雷德·艾侯 、
: Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所
: 拥有的知识。 AWK 提供了极其强大的功能:可以进行正则表达式的匹配,样式装入、
: 流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语
: 言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言: AWK 程序设计语
: 言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程
: 序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,
: 还有无数其他的功能。gawk 是 AWK 的 GNU 版本。
: 最简单地说,AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 Unix

E*V
发帖数: 17544
3
ft, awk is convenient

【在 S*A 的大作中提到】
: FT, 现在还有谁用 awk 啊。
: 大家不是都用 Python, Perl 什么的么?
:
: Unix

S*A
发帖数: 7142
4
又要记一套新的语法 :-(

【在 E*V 的大作中提到】
: ft, awk is convenient
r*****z
发帖数: 906
5
ft,awk能解决的事情,何苦上perl或者python?

【在 S*A 的大作中提到】
: FT, 现在还有谁用 awk 啊。
: 大家不是都用 Python, Perl 什么的么?
:
: Unix

r*****z
发帖数: 906
6
我相信,对于大多数有经验的*NIX用户而言,awk语法是常识

【在 S*A 的大作中提到】
: 又要记一套新的语法 :-(
S*A
发帖数: 7142
7
你写 awk 不用看 help? 佩服啊。
我现在写 python 基本上不需要看 help, 所以什么都用 python 干了。
awk 很早以前学过,后来不怎么用就忘掉了。要写肯定也可以,就是
整天看 help 写得慢。

【在 r*****z 的大作中提到】
: 我相信,对于大多数有经验的*NIX用户而言,awk语法是常识
r*****z
发帖数: 906
8
一个是学习先后的问题:学awk和perl要比学python早多了
另一个是适用范围问题:适合用awk的场景,如果改用perl或者python,
往往意味着要写“一段”程序,重复早轮子罢了

【在 S*A 的大作中提到】
: 你写 awk 不用看 help? 佩服啊。
: 我现在写 python 基本上不需要看 help, 所以什么都用 python 干了。
: awk 很早以前学过,后来不怎么用就忘掉了。要写肯定也可以,就是
: 整天看 help 写得慢。

G***y
发帖数: 1082
9
There are many jobs can be simply done by an "one-liner" in awk. They don't
require fancy syntax in awk and awk is very efficient in these situations.I
just keep a "sed one-liner" and an "awk one-liner" reference card handy.
Anything beyond that I will go for a real language.

【在 S*A 的大作中提到】
: 你写 awk 不用看 help? 佩服啊。
: 我现在写 python 基本上不需要看 help, 所以什么都用 python 干了。
: awk 很早以前学过,后来不怎么用就忘掉了。要写肯定也可以,就是
: 整天看 help 写得慢。

S*A
发帖数: 7142
10
I can do one liner with python too. It is just that my one line is really
long, wrap around and it doesn't look pretty :-<
sed I use from time to time because syntax is very close to vi.

't
.I

【在 G***y 的大作中提到】
: There are many jobs can be simply done by an "one-liner" in awk. They don't
: require fancy syntax in awk and awk is very efficient in these situations.I
: just keep a "sed one-liner" and an "awk one-liner" reference card handy.
: Anything beyond that I will go for a real language.

r*****z
发帖数: 906
11

即使不wrap,也已经不能叫“一行”了
准确来讲,应该是sed的语法很接近ed而不是vi

【在 S*A 的大作中提到】
: I can do one liner with python too. It is just that my one line is really
: long, wrap around and it doesn't look pretty :-<
: sed I use from time to time because syntax is very close to vi.
:
: 't
: .I

1 (共1页)
进入Linux版参与讨论
相关主题
dd-wrt 挂移动硬盘中文乱码的问题segmentation fault as soon as entering 1 function in the ar (转载)
unix下运行perl输出.txt文件问一下C语言编CGI的路径问题 (转载)
kde is weak to display chinse fonts?a sed question
ask a quention请问怎么把两个行数相等的文件合并起来?
Grep 能作这个吗?求助文件切割问题
how to print in matrix using AWK?在emacs中怎么按照某种格式进行替换?
C++ 初级再初级问题 (转载)sed里面正则表达式匹配字符越少越好怎么写?
这本书比较好玩shell script question
相关话题的讨论汇总
话题: awk话题: print话题: 输出话题: 输入话题: 变量