保持快乐,善于表达,敢于创新

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

FNRNR功用类似.不同的是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

程序中通过改变OFSOFMT的值,改变了指令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略有不同.

其定义如下:

表一字串, 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")

print

}

' $*

2:

去除文件中的空白行(或仅含空白字符或tab的行)

awk '$0 !~ /^[ \t]*$/ { print }' $*

3:

在文件中具有ddd-dddd (电话号码型态, ddigital)的字串前加上"TEL : "

awk '

{ gsub( /[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]/, "TEL : &" )

print

}

' $*

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)

}

print

}

' $*


TAG:

 

评分:0

我来说两句

Open Toolbar