【转】 awk 学习笔记

本文参考的是 ubuntu 下 gawk version 3.1.6 以及 《sed&awk》
一 . awk 简介

awk 是一种解释型(tawk除外)文本处理语言

二 . awk 如何运作

命令行参数
shell 会预处理命令行,获得命令行参数(其中包括命令名),之后启动命令并向它传递剩余的参数。
系统变量ARGV:
一个关联数组,存放命令行参数,数组下标从0到ARGC-1,ARGV[0]的值为awk
系统变量ARGC:
命令行参数的个数
ARGV 的元素不包含AWK的选项和脚本

笔者根据 awk 的 info 手册以及实际操作,臆测出 awk 的大致运作过程如下:
1 . 执行 -v 选项指定的赋值语句
2 . 编译awk脚本为某种内部形式(internal form)
3 . 执行 BEGIN 块
4 . #如果没有提供输入文件
    if(ARGC == 1)
    {
    #读取标准输入直到输入结束
    while(未读到到文件末尾)#文件指标准输入
    {
        读取下一个记录
        执行awk脚本
    }
    }
    #遍历存放命令行参数的数组ARGV
    for(i = 1; i < ARGC; i++) #ARGV[0]是awk,不作为输入文件
    {
    if(ARGV[i] 是var=val形式)
    {
        定义全局变量var的值为val
    }
    else  #作为文件名处理
    {
        if(ARGV[i] 是有效的文件名)
        {
            while(未读到文件 ARGV[i] 的末尾)
            {   
                读取下一个记录
                执行 awk 脚本
            }
        }
        else
        {
            输出错误,指出文件名ARGV[i]无效
        }
    }
    }
5 . 执行 END 块

从以上的流程可以看出:
1 . BEGIN 块中  可以获得步骤 1 中赋值语句的变量值
2 . BEGIN 块中不可以获得步骤 4 中赋值语句的变量值

读者可以观察以下脚本的运行结果:
$ touch file1 file2 'c=30' #创建三个文件
$ cat file1
1111
2222
$ cat file2
3333
4444
$ cat file3
5555
6666
$ cat 'c=30'  #文件名是赋值语句的形式
c=30
c=30
$ cat test1.awk
BEGIN{
    print "---------------------"
    print "当前在 BEGIN 块中"
    print "a=" a
    print "b=" b
    print "c=" c
    print "共有" ,  ARGC , "个命令行参数:"
    for(i = 0; i < ARGC; i++)
        print i , ARGV[i];
}
{
    if(FNR == 1)
    {
        print "---------------------"
        print "当前正处理文件" , FILENAME
        print "a=" a
        print "b=" b
        print "c=" c
    }
    print  "第" , FNR , "行", $0
}
END{
    print "---------------------"
    print "当前在 END 块中"
}
$ awk -v a=10 -f test1.awk file1 b=20 file2 c=30 file3
---------------------
当前在 BEGIN 块中      #注意到BEGIN只执行一次,而且是在输入之前
a=10                   #BEGIN块里只认识通过 -v 选项赋值的变量a
b=                     # 不认识
c=                     # 不认识
共有 6 个命令行参数:   #注意到,参数里面没有选项(-f)
0 awk                  #也没有作为脚本的文件名test1.awk
1 file1
2 b=20
3 file2
4 c=30
5 file3
---------------------
当前正处理文件 file1
a=10                   #-v 选项赋值的变量,所有文件都认识
b=                     # 读入file1之后b=20才执行,file1不认识b
c=                     # c 是谁file1也不知道
第 1 行 1111
第 2 行 2222
---------------------
当前正处理文件 file2
a=10                   #-v 选项赋值的变量,所有文件都认识
b=20                   #b=20发生之后才读入file2,所以认识b
c=                     #肯定不认识
第 1 行 3333
第 2 行 4444
---------------------
当前正处理文件 file3
a=10
b=20
c=30                   #原来,尽管当前目录下有名叫'c=30'的文件,但awk仍然把它当成赋值语句了
第 1 行 5555
第 2 行 6666
---------------------
当前在 END 块中        #注意到END发生在所有输入完毕之后
$

三 . 字符串常量
字符串常量是包括在两个双引号之间的一系列字符。
awk 能够像 C 语言一样识别字符串常量中如下转义字符:
//        字面反斜杠
/a        响铃(alert)
/b        退格键(backspace)
        作用:删除光标左边的字符并使光标左移一格
/f        进纸键(form-feed)
        作用:不清楚
/n        新行符(newline character)
/r        回车符(carriage return)
/t        水平制表符(horizontal tab)
/v        垂直制表符(vertical tab)
/xhexdigits     转义/x之后的 16 进制字符串为对应的字符
        /x1B 代表 ESC 字符
/ddd        将 一位,两位,三位的十进制数转化为对应的字符
        /033 或 /33 代表 ESC 字符
/c        字面的 字符 c

注意:
以上转义序列能够被 awk 的正则表达式识别!!

四 . 正则表达式

gawk 默认支持 POSIX ERE , GAWK 独有的转义序列, 以及 gawk 字符串常量支持的 C 类的转义序列。

POSIX ERE 支持以下形式的正则表达式:
c        匹配单个非元字符c
/c        匹配字面的元字符c
^        匹配字符串开始
$        匹配字符串结束
.        匹配任意字符,含换行符
[]        匹配方括号中出现的任意字符
[^]        匹配其中没有出现的字符
REGEXP1|REGEXP2    匹配REGEXP1 或者 REGEXP2
REGEXP1REGEXP2    匹配REGEXP1 紧接着匹配 REGEXP2
REGEXP+        匹配REGEXP 的一次及以上出现
REGEXP?        匹配REGEXP 的 0 次或 1 次出现
REGEXP*        匹配REGEXP 的 0 次及以上出现
(REGEXP)    匹配REGEXP , 分组
REGEXP{n}    匹配REGEXP的 n 次出现
REGEXP{n,m}    匹配REGEXP的 n 到 m 次出现
REGEXP{n,}       匹配REGEXP的 最少 n 次出现
REGEXP{,m}    匹配REGEXP的 最多 m 次出现
字符类        [:alnum:]等
等价类        [=e=]等
collating class [.ch.] 等

GAWK 独有的转义序列
/y        匹配单词开头或者结尾的空串
/B        匹配单词内部的空串
/`        匹配缓冲区开头的空串
/'        匹配缓冲区结尾的空串
/w        匹配字母数字下划线(word-constituent character)
/W        匹配非字母数字下划线(no word-constituent character)
/<        匹配单词开头的空串
/>        匹配单词结尾的空串

awk 支持的 C 类转义序列也被 gawk 正则表达式支持:
/n
/r
/t
/v
/a
/b
/xhexdigits
/ddd

五 . 选项

-F fs
指定fs 为字段分隔符(field separator)

-f script
将script的内容添加到脚本中去。
-f可以出现多次,awk会按顺序把所有的脚本文件拼接作为一个完整的脚本

-v var=val
设置变量var 的值为 val,改变量赋值发生在BEGIN块之前
如果在赋值语句var=val中出现空格,可以使用引号将该语句包围,以此保护空格

以下选项关乎awk对正则式的理解:

--posix
支持POSIX ERE(包括范围表达式)
支持 awk 字符串常量支持的转义字符
不支持上述 GAWK 独有的转义序列

--traditional
只支持传统的UNIX awk 正则表达式,以下均不支持:
1) 范围表达式
2) 字符类等
3) gawk 独有的转义序列(更加不支持了!)
4)  awk 字符串常量所支持的那些 C 类转义序列

--re-interval
强制支持范围表达式,即使已经指定了 --traditional 选项

如果上诉三种选项均未指定,则 awk 对正则式作如下理解:
支持 POSIX ERE (除了范围表达式)
支持 GAWK 支持的特殊转义序列(/y /w等)
支持  AWK 字符串常量支持的特殊转义字符(/ddd等)

五 . 记录和字段
1 . 记录(record)
1) 记录默认由新行符分隔,新行符是内置系统变量记录分隔符RS(record separator)的值。
2) RS 通常是一个字符,这个字符用于分隔记录。
3) RS 如果是多个字符,则被作为正则表达式,输入文本中匹配该正则式的部分用于隔开记录。但是在兼容模式下,只取第一个字符被作为分隔符。
4) <<sed & awk>> :RS 是 awk 仅仅注意其第一个字符的唯一一个变量。
3) RS 设置为空串(""),则记录被空行分隔,此时,无论FS(域分隔符)被设置成什么值,字段是由新行符隔开的。
4) FNR 记录当前记录在当前输入文件中的编号,即当前记录是当前文件的第 FNR 个记录。
5) NR 记录已经读入的记录的个数

2 . 字段(field)
1) 字段分隔符FS(field separator)用于把记录分隔成多个字段
2) FS通常是单个字符,则字段由该字符分隔。
3) FS是空格时比较特殊,记录中的字段之间由任意数量空格,任意数量制表符的任意排列分隔。
4) FS含多个字符时被作为正则表达式
5) NF 记录当前记录中的字段数
6) FIELDWIDTH 变量一旦被设置,则 FS 的值会被忽略,即在字段分隔不起作用。
7) awk读入记录的同时把字段的值赋给了内置变量,有以下方式可引用字段:
----使用常量引用例如 $10
----使用变量引用例如 $i  , $NF
----使用算式返回值例如 $(2+1)
----使用函数返回值引用例如 $int(1+1)

其中,美元符叫做字段引用操作符
8) 引用负数位置的字段将导致错误
9) 引用 $NF 之后的字段将导致 awk 自动生成该字段及之前本没有的字段并各赋值为空串,NF被修改,$0 被调整。

六 . 关联数组

awk 中所有的数组都是关联数组,表达了一种从字符串到字符串的映射关系。

1 . 关联数组特点
1) 物理组织无序
2) 模拟多维数组
3) 原理是字符串映射

2 . 下标
关联数组的下标是括在一对方括号之间的表达式列表,如果有多个表达式,则表达式间用英文逗号分隔。
1)  一维数组
数组是从一个字符串到另一个字符串的映射,key_str --> val_str ,前者是键。
-- arr[ key_str ] 形式,awk 访问以变量   key_str 的值为键的数组元素
   有个例外,当 key_str 是一个数字时,awk 会把它转换为字符串,此时arr[key_str]等价于arr["key_str"]
-- arr["key_str"] 形式,awk 访问以字符串 key_str     为键的数组元素
-- 访问某个不存在的数组元素时,awk会创建该数组元素,数组元素初始化为空串

例子:
$ awk 'BEGIN{a[1] = "1111";  print "a[/"1/"]=" , a["1"];  print "a[ 1 ]=" , a[1] }' file
a["1"]= 1111
a[ 1 ]= 1111
$ awk 'BEGIN{a["1"] = "111"; print length(a); print a[var] ; print length(a)}' file
1                 # print length(a)输出 a 的长度,当时有一个元素 a["1"]
                  # a[var] 相当于 print a[""],而a[""]元素不存在,输出空串
2                 # awk 自动创建了数组元素 a[""]并初始化为空串 , 所以数组大小变为 2
$

2)  多维数组
多维数组通过在方括号之间用逗号隔开各维的键进行访问,所有的键值都被作为字符串。
数字键会被转换为字符串,其中,实数转换为字符串可能会丢失信息,实数转换受 CONFMT 的影响。
多维数组与一维数组遵循同样的映射原理:
通过把方括号中各字符串用系统变量 SUBSEP 的值衔接起来得到 key_str ,然后映射到 val_str 。

例子:
i = "30"
j = 20
a["mm",i,j] = "zhong"      相当于   a["30" , "30" , 20] = "zhong"
                           相当于   a["mm" , "30" , "20"] = "zhong"

意为把数组元素 a["mm/03430nn"] 赋值为串 "zhong",其中/034 是SUBSEP 的默认值。

3 . 删除
通过 delete arr["index"] 删除单个元素;delete arr 删除整个数组。

4 . 遍历
---方法1
while(key in arr) #遍历 arr 的所有键值,如果是多维数组,用(key1,key2,key3)放在 key 的位置。

---方法2
如果能够在构建数组的时候,用连续的或者大小有规律的键值,则可以用for循环遍历例如:
for(i = 1; i <= NF; i++)
    arr[i] = $i;
for(i = 1; i <= NF; i++)
    print arr[i];

六 . 操作符(按优先级逐渐降低)
()        分组操作符
$        字段引用操作符
++ --        递增递减
^        指数
+ - !        一元加,一元减,逻辑取反
* / %        乘除取模
+ -        二元加,二元减
space        字符串连接符,很牛逼!
| |&        管道I/O,用于print , printf,getline
< >        关系运算符
<= >=
!= ==        
~ !~        匹配,不匹配,字符串匹配的,超牛逼!
in        判断关联数组中是否存在以某个键为下标的元素
&&        逻辑与
||        逻辑或
?:        C格式的条件语句,expr?expr1:expr2,如果expr为真,则该条件语句值为expr1的值;否则expr2。
= += -=        赋值,^=是将指数运算的结果赋给左参数
*= /= %= ^=

八 . 语句格式
awk 程序的框架是由一个或者多个如下的语句组组成:
condition{ statements }

其中可能出现两个特殊语句组
BEGIN{ statements }  和  END{ statements }

1 . BEGIN 语句组(如果有),作为第一个语句组,-v选项赋值语句之后,第一个记录读入之前执行。
2 . END 语句组(如果有),作为最后一个语句组。在所有输入结束之后执行。
3 . 每次读入一个记录,剩下的语句组都要判断条件是否满足,如果满足就执行。
4 . condition{statements}的condition如果缺失,则对所有记录都执行方括号中的语句。
5 . statements 如果缺失,则默认执行 print 函数,输出 $0
6 . 左花括号({) 必须和condition在同一行,condition 和 { 之间可以隔着空白符。
7 . statements中的每个statement 可以用分号隔开

condition 语句可以是以下形式:

BEGIN
-v选项赋值语句之后,第一个记录读入之前执行方括号中的语句。

END
在所有输入结束之后执行方括号中的语句。

/REGEXP/
当前记录能够匹配正则表达式REGEXP时,才执行方括号中的语句。
正则式的匹配能力须参考上面的部分。

表达式
《sed&awk》:表达式通过计算返回一个值,表达式由数字,字符串常量,变量,操作符,函数和正则表达式组成。
利用表达式的值作为判断根据,如果为0或者空则不执行

condition && condition 和  condition || condition
表示两个条件的逻辑与 和 逻辑或

condition ? condition1 : condition2
当condition满足时,如果condition1满足则执行方括号中的语句;
否则,当condition2满足时则执行方括号中的语句。

(condition)
就是把条件用括号包围起来而已

! condition
当condition不满足时,才执行方括号中的语句。

condition1 , condition2
从第一个满足condition1的记录开始(包含),到该记录之后第一个满足condition2的记录结束(含该记录)
都执行方括号中的语句。

例子:
# 不是BEGIN的条件下
! BEGIN{ statements }

# 注意左花括号之前可以有很多空白符
# 注意使用圆括号将表达式括起来不是必须的
0{ statements_impossible_to_execute }
1 - 1{ statements_impossible_to_execute }
(1+1)    { statements_doomed_to_excute }

# 注意匹配的是扩展的正则表达式(ERE)
/^/t+/{ statements }

# 注意使用ERE的范围表达式时需要有 --posix 或者 --re-interval 选项
awk --posix '/a{2,4}/{print}' data

八 . 系统变量

FS        字段分隔符
RS        记录分隔符
OFS        输出字段分隔符,默认为空格;影响print的输出。
        print $0 输出当前记录,字段之间由OFS的值隔开;
        print "a" , "b" a和 b 之间由 OFS值隔开。
ORS        输出记录分隔符,默认为新行符;影响print的输出。
        每个 print 语句最后都会输出 ORS    的值
ARGV        关联数组,用于存储传递给 awk 的输入文件名
        有 ARGC    个元素,下标因此从0 到 AGRC-1
        ARGV[0] 等于 "awk"
        ARGV中的文件名如果是等式形式,则被awk作为赋值语句。
ARGC        数组ARGV中元素的个数,ARGC>= 1; 因为 ARGV[0] 是 "awk"
FNR        当前记录在当前输入文件中的位置,即当前文件的第FNR个记录
FILENAME    当前输入文件
RSTART        参考match 函数
RLENGTH        参考match 函数
SUBSEP        在多维数组的字符串映射中,用于把各维的键值衔接起来形成整体的键值
        默认值是 "/034"
CONVFMT        数字转换的格式,默认值"%.6g"
ENVIRON        以环境变量名(大写)为键值的关联数组,可以通过环境变量名访问数组元素。
OFMT        数字的输出格式,默认是"%.6g"

还有一些系统变量,不熟悉,不写了:
ERRNO    IGNORECASE LINT    PROCINFO TEXTDOMAIN RT

九 . statements
statements 支持 C-style 条件和循环语句,break,continue ;以及其它语句。
------------------------------------------------------------------------------------
if(条件){语句组}[else {语句组}]
while(条件){语句组}
do{语句组}while(条件)
for(语句1;语句2;语句3){语句组}
for(var_key in arr){语句组}
break
continue
delete arr[i]
delete arr
exit [exitcode]

十 . 函数

1 . 算术函数
int ()
返回强制转换后得到的整数
cos(expr)
返回余弦值
sin(expr)
返回正弦值
atan2(y,x)
返回以弧度计算的(y/x)的反正切值
loh(expr)
返回自然对数值
exp(expr)
返回对数值
sqrt(expr)
返回开方后的值
rand()
返回随机产生的小于1大于等于0的值
srand([expr])
设置rand()函数的种子值为 expr 的返回值,如果没有expr 则以当天时间为种子。
<<sed&awk>>:如果没有调用srand(),awk在开始执行程序之前默认以某个常量为参数调用srand(),使得你的程序在每次运行时都从同一个种子数开始。

2 . 字符串函数
length()
返回字符串或者数组的长度

index(str,target)
返回字符串 target 在字符串 str 中第一次出现的位置,如果没有,返回 0;字符串下标从 1 开始。

match(str , /regexp/ , [, arr])
在字符串 str 中寻找匹配 regexp 的子串,返回第一个匹配子串的位置,如果失配,返回0。
设置系统变量 RSTART 为匹配子串的起始位置,RLENGTH为匹配子串的长度;失配则RSTART为 0 ,RLENGTH 为 -1。
如果 arr 这个数组,则 arr 被清空,并从下标 "1" 开始保存找到的匹配regexp的子串。
所有匹配的子串被保存在 arr["0"] 中。

split(str , arr [, /separator_regexp/])
把字符串 str 分解到数组 arr 中去,使用匹配正则式 separator_regexp 的子串作为分隔符。
如果没有提供 serarator_regexp 则使用 FS 的值作为分隔符。
返回分解得到的串的个数,即数组的大小(如果有)

sub(/regexp/ , replacement [,str])
把 str 中第一个匹配正则式 regexp 的子串替换成 replacement 字符串。返回替换的个数。
如果没有提供 str ,使用 $0 。
replacement 中出现的 & 具有特殊含义,被替换成匹配 regexp 的那部分子串。
要转义 replacement 中的 & 使用 //&
此外,& 必须被包含在双引号之间才能被识别,否则出错。

gsub(/regexp/ , replacement [,str])
把 str 中所有匹配正则式 regexp 的子串替换成 replacement 字符串。返回替换的个数。
其余说明与 sub 同。

tolower(str)
返回字符串 str 中所有大写字母全部被转换为小写字母之后的串。原串不改变。

toupper(str)
返回字符串 str 中所有小写字母全部被转换为大写字母之后的串。原串不改变。

substr(str , pos [,len])
返回 str 第 pos 个字符开始的长度为 len (len >=1) 的串
如果 len 未提供,则返回直到 str 末尾的串
如果 len <= 0 则返回空串

3 . 自定义函数

格式
function func_name(parameter_list){
    statements;
    return [rt_val]
}

1) 定义函数时,func_name 和左圆括号之间可以有空格,但是调用函数时不允许。系统自带函数例外。
2) 自定义函数中定义的变量具有全局性质,将它们定义在圆括号内的形式参数之后,可使成为局部变量。
3) 调用自定义函数时,实际参数不必包括函数内的局部变量。
4) 应该具有返回值,如果不显式返回,则默认返回空串。
5) <<sed&awk>>:自定义函数的定义可以放在脚本中模式操作规则可以出现的任何地方,通常可以放在脚本中模式操作规则之前。

4 . print

1) print
输出 $0 , 后跟 ORS

2) print expr_list
---每个表达式(expr)之间用逗号和空格的组合进行分隔。
---每个表达式的结果会被作为字符串输出,表达式之间输出OFS的值
---print 语句的最后输出 ORS 的值
---单个表达式内的串之间的空格符是作为字符串衔接符(print "x" "y" 相当于 print "xy")
---可以重定向到文件
---<<sed&awk>>: 规定 > 出现在任何打印语句的参数列表中时被看作是重定向操作符,如果想要 > 在参数列表中被看作关系运算符,可以使用圆括号将表达式或者参数列表括起来。

5 . printf("format_expression" [, arguments])
借用C程序设计语言printf进行格式化输出,括号可以省略。
format_expression 由双引号括起来,其中%之后的字符作为格式转换说明符; arguments 由逗号分隔,第 n 个
argument 对应于 format_expression 第 n 个 %转义说明符; 意为把该 argument
对应的串转换为该格式转换说明符指明的格式并输出。

以下为 % 与格式转换说明符的组合:
%c        作为ASCII字符输出
%d        作为整数输出
%i        作为整数输出
%e        以浮点格式输出
%E        以浮点格式输出
%f        以浮点格式输出
%g        e或f的转换格式,长度最短,末尾的 0 被去掉
%G        E或f的转换格式,长度最短,末尾的 0 被去掉
%O        作为无符号八进制数输出
%s        作为字符串输出
%u        作为无符号的十进制数输出
%x        作为无符号的十六进制数输出,a-f表示 10-15
%X        作为无符号的十六进制数输出,A-F表示 10-15
%%        字面的%

上述每一个格式转换说明符(除了%%之外)都可以扩充为以下形式:
        %-width.precision format_specifier
width 指定域宽度,指定域宽的输出会自动向右对齐,如果想想左对齐,可以在百分号之后添加减号(-),见上式。
pricision 指定小数点之后的数字位数
数字的默认转换格式由系统变量 CONFMT (有的是OFMT) 指定,默认为 "%.6g"

也可以是以下形式:
        % width.precision format_specifier
        %0width.precision format_specifier
        %+width.precision format_specifier
        %#width.precision format_specifier

关于 printf 函数,不熟悉,只把参考文件贴出来:
-      The expression should be left-justified within its field.

space  For  numeric  conversions,  prefix positive values with a space,
       and negative values with a minus sign.

+      The plus sign, used before the width modifier (see below),  says
       to  always  supply  a  sign for numeric conversions, even if the
       data to be formatted is positive.  The  +  overrides  the  space
       modifier.

#      Use  an  “alternate  form” for certain control letters.  For %o,
       supply a leading zero.  For %x, and %X, supply a leading  0x  or
       0X  for  a  nonzero  result.   For %e, %E, %f and %F, the result
       always contains a decimal point.  For %g, and %G, trailing zeros
       are not removed from the result.

0      A  leading 0 (zero) acts as a flag, that indicates output should
       be padded with zeroes instead of spaces.  This applies  even  to
       non-numeric  output  formats.  This flag only has an effect when
       the field width is wider than the value to be printed.

width  The field should be padded to this width.  The field is normally
       padded  with  spaces.  If the 0 flag has been used, it is padded
       with zeroes.

.prec  A number that specifies the precision to use when printing.  For
       the  %e,  %E,  %f  and %F, formats, this specifies the number of
       digits you want printed to the right of the decimal point.   For
       the  %g, and %G formats, it specifies the maximum number of sig‐
       nificant digits.  For the %d, %o, %i, %u, %x, and %X formats, it
       specifies  the  minimum  number  of digits to print.  For %s, it
       specifies the maximum number of characters from the string  that
       should be printed.

6 . getline

1) getline
读取下一个记录,覆盖$0,设置FNR NR NF

2) getline "-"
从标准输入读取一行

3) getline <"filename"
读入文件filename的下一个记录,只更新NF

4) getline var
读取下一个记录,存入变量var ,设置 FNR NR。 $0 不变,NF 不变

5) getline var <"file_name"
读入文件file的下一个记录,存入变量var 。 FNR NR NF $0均不变。

注:
1) 不能写成 getline() , 它的语法不允许有圆括号。
2) 返回值不是字符串
3) 成功读取返回 1 ;读到文件末尾返回 0 ;遇到错误返回 -1
4) 从流中/文件/管道中读取时,可以直接以字符串常量指定文件名,也可以通过变量提供。

7 . close

用于关闭已经打开的文件或管道,以此可以
1)限制打开的文件和管道的数量
2)关闭一个管道可以运行同一个命令两次
3)关闭一个管道使得其输出的成果可以被访问

例子2):
$ cat test.awk
{
    "date" | getline var
    print var
    close("date")            #关闭管道
    "date" | getline var2
    print var2
}
$ awk -f test.awk file
Fri Mar  4 21:35:09 CST 2011
Fri Mar  4 21:35:09 CST 2011
$ cat test.awk
{
    "date" | getline var
    print var
#    close("date")            #不关闭管道
    "date" | getline var2
    print var2
}
$ awk -f test.awk file            #产生空行
Fri Mar  4 21:35:09 CST 2011

$

例子3):
$ cat test.awk
{
    print $0 | "sort > outcome"
}
END{
    close("sort > outcome")  #关闭管道
    while(getline var<"outcome"){
        print var
    }
}
$ cat data
aa
bb
ff
cc
$ awk -f test.awk data
$ cat outcome
aa
bb
cc
ff
$

8 . next

读入下一个记录,修改$0,NF ,NR , FNR
如果已经读到文件末尾,那么执行END块(如果有)
否则从第一个 condition{statements}重新开始执行
例子:
$ cat test.awk
{
    print "next 前"
    print "$0 =" $0
    print "FNR=" FNR
    print "NF =" NF
    print "NR =" NR
    next
    print "next 后"
    print "$0 =" $0
    print "FNR=" FNR
    print "NF =" NF
    print "NR =" NR
}
END{
    print "在 END 中"
}
$ cat data
aa bb
aa bb cc dd
$ awk -f test.awk data
next 前
$0 =aa bb            #file的第一行
FNR=1
NF =2
NR =1
next 前                #注意,不是 "next 后"
$0 =aa bb cc dd            #file的第二行
FNR=2
NF =4
NR =2
在 END 中
$

9 . nextfile
读入下一个文件的第一个记录,修改$0 , NF , NR , FNR
如果发现所有文件的输入数据都已经读完,执行END块(如果有)
否则从第一个 condition{statements}重新开始执行

10 . exit
exit 使得主输入循环退出并将控制转移到 END 规则,如果END存在的话。

11 . system("command_line")
执行 command_line , 返回命令的退出状态(exit status)

补充内容:
1 . 关于注释
与 sed 不同,awk 允许在程序的任何地方添加注释

2 . 关于断行的技巧
一种处理断行的方法就是使用 length 获得每个字段的长度,这样,当累计的长度超过某个特定的数据时,就可以指定一个换行。

3 . 看不懂的
注意, awk 和sed 不一样,不能“记住”前面的正则式,即不能用语法// 来引用最后的正则表达式。

第八章,有两个语句能影响输入循环,next 和 exit 。一些 awk 不允许在用户自定义的函数中使用 next 语句。exit
使得主输入循环退出并将控制转移到 END 规则,如果 END 存在的话。如果没有定义END 规则或者在end 中使用exit 则终止脚本的执行。

转自:http://blog.csdn.net/yaozhiyi/article/details/6224847

上一篇:GraphQL搭配MongoDB入门项目实战


下一篇:[原创]手把手教你写网络爬虫(7):URL去重