awk manual-7
上一篇 / 下一篇 2008-06-23 14:07:38 / 个人分类:Shell编程
15. 附录D ── awk的內建变量Built-in Variables
因內建变量的个数不多,此处按其相关性分类说明,并未按其字母顺序排列.
l ARGC
ARGC表示命令行上除了选项-F, -v, -f及其所对应的参数之外的所有参数的个数.若将"awk程式"直接写於命令列上,则ARGC亦不将该"程式部分"列入计算.
l ARGV
ARGV数组用以记录命令列上的参数.
例:执行下列命令
$ awk -F\t -v a=8 -f prg.awk file1.dat file2.dat
或
$ awk -F\t -v a=8 '{ print $1 * a }' file1.dat file2.dat
执行上列任一程式后
ARGC = 3
ARGV[0] = "awk"
ARGV[1] = "file1.dat"
ARGV[2] = "file2.dat"
读者请留心:当ARGC = 3时,命令列上仅指定了2个文件.
注:
-F\t表示以tab为栏位分隔字符FS(field seporator).
-v a=8是用以初始化程序中的变量a.
l FILENAME
FILENAME用以表示目前正在处理的文件档名.
l FS
栏位分隔字符.
l $0
表示目前awk所读入的数据行.
l $1,$2..
分別表示所读入的数据行之第一栏,第二栏,..
说明:
当awk读入一笔数据行"A123 8:15"时,会先以$0记录.
故$0 = "A123 8:15"
若程序中进一步使用了$1, $2..或NF等內建变量时, awk才会自动分割$0.
以便取得栏位相关的资料.切割后各个栏位的资料会分別以$1, $2, $3...予以记录.
awk內定(default)的栏位分隔字符(FS)为空白字符(空格及tab).
以本例而言,读者若未改变FS,则分割后:
第一栏($1)="A123", 第二栏($2)="8:15".
使用者可用正则表达式自行定义FS. awk每次需要分割数据行时,会参考目前FS的值.
例如:
令FS = "[ :]+"表示任何由空白" "或冒号":"所组成的字串都可当成分隔字符,则分割后:
第一栏($1) = "A123",第二栏($2) = "8",第三栏($3) = "15"
l NR
NR表从awk开始执行该程序后所读取的数据行数.
l FNR
FNR与NR功用类似.不同的是awk每打开一个新的文件,FNR便从0重新累计
l NF
NF表目前的数据行所被切分的栏位数.
awk每读入一笔资料后,在程序中可以NF来得知该行数据包含的栏位个数.在下一笔资料被读入之前, NF并不会改变.但使用者若自行使用$0来记录数据,例如:使用getline ,此时NF将代表新的$0上所记载的资料的栏位个数.
l OFS
OFS输出时的栏位分隔字符.预设值" "(一个空白),详见下面说明.
l ORS
ORS输出时数据行的分隔字符.预设值"\n"(跳行),见下面说明.
l OFMT
OFMT数值资料的输出格式.预设值"%.6g"(若须要时最多印出6位小数)
当使用print指令一次印出多项资料时,
例如: print $1, $2
输出时, awk会自动在$1与$2之间补上一个OFS之值
每次使用print输出后, awk会自动补上ORS之值.
使用print输出数值数据时, awk将采用OFMT之值为输出格式.
例如:
$ awk 'BEGIN { print 2/3,1; ōFS=":"; ōFMT="%.2g"; print 2/3,1 }'
输出:
0.666667 1
0.67:1
程序中通过改变OFS和OFMT的值,改变了指令print的输出格式.
l RS
RS( Record Separator) : awk从文件上读取资料时,将根据RS的定义把资料切割成许多Records,而awk一次仅读入一个Record,以进行处理.
RS的预设值是"\n".所以一般awk一次仅读入一行资料.
有时一个Record含括了几行资料(Multi-line Record).这情況下不能再以"\n"
来分隔相邻的Records,可改用空白行来分隔.
在awk程式中,令RS = ""表示以空白行来分隔相邻的Records.
l RSTART
RSTART与使用字串函数match( )有关的变量,详见下面说明.
l RLENGTH
RLENGTH与使用字串函数match( )有关之变量.
当使用者使用match(...)函数后, awk会将match(...)执行的结果以RSTART,RLENGTH记录.
请参考附录C awk的內建函数match().
l SUBSEP
SUBSEP(Subscrīpt Separator)数组下标的分隔字符,
预设值为"\034"实际上, awk中的数组只接受字串当它的下标,如: Arr["John"].
但使用者在awk中仍可使用数字当阵列的下标,甚至可使用多维的数组(Multi-dimenisional Array)如: Arr[2,79]
事实上, awk在接受Arr[2,79]之前,就已先把其下标转换成字串"2\03479",之后便以Arr["2\03479"]代替Arr[2,79].
可参考下例:
awk 'BEGIN {
Arr[2,79] = 78
print Arr[2,79]
print Arr[ 2 , 79 ]
print Arr["2\03479"]
idx = 2 SUBSEP 79
print Arr[idx]
}
' $*
执行结果输出:
78
78
78
78
16. 附录E ──正则表达式(Regular Expression)简介
l 为什么要使用正则表达式
UNIX中提供了许多指令和tools,它们具有在文件中查找(Search)字串或替换(Replace)字串的功能.像grep, vi , sed, awk,...
不论是查找字串或替换字串,都得先告诉这些指令所要查找(被替换)的字串为何.若未能预先明确知道所要查找(被替换)的字串为何,只知该字串存在的范围或特征时,例如:
(一)找寻"T0.c", "T1.c", "T2.c".... "T9.c"当中的任一字串.
(二)找寻至少存在一个"A"的任意字串.
这情況下,如何告知执行查找字串的指令所要查找的字串为何.
例(一)中,要查找任一在"T"与".c"之间存在一个阿拉伯数字的字串;当然您可以列举的方式,一一把所要找寻的字串告诉执行命令的指令.但例(二)中合乎该条件的字串有无限种可能,势必无法一一列举.此时,便需要另一种字串表示的方法(协定).
l 什么是正则表达式
正则表达式(以下简称Regexp)是一种字串表达的方式.可用以指定具有某特征的所有字串.
注:为区別于一般字串,本附录中代表Regexp的字串之前皆加"Regexp". awk程式中常以/..../括住Regexp;以区別于一般字串.
l 组成正则表达式的元素
普通字符除了. * [ ] + ? ( ) \ ^ $外之所有字符.
由普通字符所组成的Regexp其意义与原字串字面意义相同.
例如: Regexp "the"与一般字串的"the"代表相同的意义.
. (Meta. character) :用以代表任意一字符.
须留心UNIX Shell中使用"*"表示Wild card,可用以代表任意长度的字串.而Regexp中使用"."来代表一个任意字符.(注意:并非任意长度的字串)Regexp中"*"另有其它涵意,并不代表任意长度的字串.
^表示该字串必须出现于行首.
$表示该字串必须出现于行末.
例如:
Regexp /^The/用以表示所有出现于行首的字串"The".
Regexp /The$/用以表示所有出现于行末字串"The".
\将特殊字符还原成字面意义的字符(Escape character)
Regexp中特殊字符将被解释成特定的意义.若要表示特殊字符的字面(literal meaning)意义时,在特殊字符之前加上"\"即可.
例如:
使用Regexp来表示字串"a.out"时,不可写成/a.out/.
因为"."是特殊字符,表任一字符.可符合Regexp / a.out/的字串将不只"a.out"一个;字串"a2out", "a3out", "aaout" ...都符合Regexp /a.out/ 正确的用法为: / a\.out/
[...]字符集合,用以表示两中括号间所有的字符当中的任一个.
例如:
Regexp /[Tt]/可用以表示字符"T"或"t".故Regexp /[Tt]he/表示字串"The"或"the".
字符集合[...]內不可随意留空白.
例如: Regexp /[ Tt ]/其中括号內有空白字符,除表示"T", "t"中任一个字符,也可代表一个" "(空白字符)
-字符集合中可使用"-"来指定字符的区间,其用法如下:
Regexp /[0-9]/等于/[0123456789]/用以表示任意一个阿拉伯数字.
同理Regexp /[A-Z]/用以表示任意一个大写英文字母.
但应留心:
Regexp /[0-9a-z]/并不等于/[0-9][a-z]/;前者表示一个字符,后者表示二个字符.
Regexp /[-9]/或/[9-]/只代表字符"9"或"-".
[^...]使用[^..]产生字符集合的补集(complement set).
其用法如下:
例如:要指定"T"或"t"之外的任一个字符,可用/[^Tt]/表之.
同理Regexp /[^a-zA-Z]/表示英文字母之外的任一个字符.
须留心"^"的位置: "^"必须紧接於"["之后,才代表字符集合的补集
例如:Regexp /[0-9\^]/只是用以表示一个阿拉伯数字或字符"^".
*形容字符重复次数的特殊字符.
"*"形容它前方之字符可出现1次或多次,或不出现(0次).
例如:
Regexp /T[0-9]*\.c/中*形容其前[0-9] (一个阿拉伯数字)出现的次数可为0次或多次.故Regexp /T[0-9]*\.c/可用以表示"T.c", "T0.c", "T1.c"..."T19.c"
+形容其前的字符出现一次或一次以上.
例如:
Regexp /[0-9]+/用以表示一位或一位以上的数字.
? 形容其前的字符可出现一次或不出现.
例如:
Regexp /[+-]?[0-9]+/表示数字(一位以上)之前可出现正负号或不出现正负号.
(...)用以括住一群字符,且将之视成一个group(见下面说明)
例如:
Regexp /12+/ 表示字串"12", "122", "1222", "12222",...
Regexp /(12)+/表示字串"12", "1212", "121212", "12121212"....
上式中12以( )括住,故"+"所形容的是12,重复出现的也是12.
|表示逻辑上的"或"(or)
例如:
Regexp / Oranges? | apples? | water/可用以表示: 字串"Orange", "Oranges"或"apple", "apples" 或"water"
l match是什么?
讨论Regexp时,经常遇到"某字串匹配( match )某Regexp"的字眼.其意思为: "这个Regexp可被解释成该字串".
[例如] :
字串"the"匹配(match) Regexp /[Tt]he/.
因为Regexp /[Tt]he/可解释成字串"the"或"The",故字串"the"或"The"都匹配(match) Regexp /[Th]he/.
l awk中提供二个关系运算符(Relational Operator,见注一) ~ !~,
它们也称之为match, not match.但函义与一般常称的match略有不同.
其定义如下:
A 表一字串, B表一Regular Expression
只要A字串中存在有子字串可match(一般定义的match) Regexp B ,则A ~B就算成立,其值为true,反之则为false.
! ~的定义与~恰好相反.
例如:
"another"中含有子字串"the"可match Regexp /[Tt]he/ ,所以
"another" ~ /[Tt]he/ 之值为true.
[注一] :有些论著不把这两个运算符( ~, !~)与Relational Operators归为一类.
l 应用Regular Expression解题的简例
下面列出一些应用Regular Expression的简例,部分范例中会更改$0之值,若您使用的awk不允许用户更改$0时,请改用gawk.
例1:
将文件中所有的字串"Regular Expression"或"Regular expression"换成"Regexp"
awk '
{ gsub( /Regular[ \t]+[Ee]xpression/, "Regexp")
}
' $*
例2:
去除文件中的空白行(或仅含空白字符或tab的行)
awk '$0 !~ /^[ \t]*$/ { print }' $*
例3:
在文件中具有ddd-dddd (电话号码型态, d表digital)的字串前加上"TEL : "
awk '
{ gsub( /[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]/, "TEL : &" )
}
' $*
例4:
从文件的Fullname中分离出路径与档名
awk '
BEGIN{
Fullname = "/usr/local/bin/xdvi"
match( Fullname, /.*\//)
path = substr(Fullname, 1, RLENGTH-1)
name = substr(Fullname, RLENGTH+1)
print "path :", path," name :",name
}
' $*
结果印出
path : /usr/local/bin name : xdvi
例5:
将某一数值改以现金表示法表示(整数部分每三位加一撇,且含二位小数)
awk '
BEGIN {
Number = 123456789
Number = sprintf("$%.2f",Number)
while( match(Number,/[0-9][0-9][0-9][0-9]/ ) )
sub(/[0-9][0-9][0-9][.,]/, ",&", Number)
print Number
}
' $*
结果输出
$123,456,789.00
例6:
把文件中所有具"program数字.f"形态的字串改为"[Ref : program数字.c]"
awk '
{
while( match( $0, /program[0-9]+\.f/ ) ){
Replace = "[Ref : " substr( $0, RSTART, RLENGTH-2) ".c]"
sub( /program[0-9]+\.f/, Replace)
}
}
' $*
TAG:
标题搜索
日历
|
|||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
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 |
我的存档
数据统计
- 访问量: 48173
- 日志数: 70
- 建立时间: 2007-07-05
- 更新时间: 2011-11-08