awk学习笔记
awk程序由awk命令、括在引号(或写在文件)中的程序指令(可以有几个)以及输入文件的文件名组成,如果没有制定输入文件,输入则来自标准输入(stdin),即键盘。awk指令由模式、操作,或模式与操作的组合组成。模式是bool语义,由多个括在两个正斜杠之间的regexp表达式或布尔表达式组成;操作由括在大括号内的一条或多条语句组成,语句间分号隔开。
在文件中的程序指令唯独少了引号,这部分指令为如下格式:
- 模式 { 操作语句; 操作语句; 。。。;}
- 模式 {
操作语句
操作语句
}
同sed一样,awk是一行一行的进行处理的,每一行的流程如下:
- awk使用一行(也叫记录,以换行符结束)作为输入,并将这一行赋给内部变量$0
- 行被空格分解成字段(单词),每一个字段存储在已编号的变量中,从$1开始(这一点和sed不同,后者是将一行看作一个字符流)
- 内部变量FS来确定字段的分隔符(流程2),默认是空格和\t,可以自己定义另外的分隔符。
- 根据模式的真假,确定是否进行操作,没有操作打印整行,没有模式,默认为真
简单输出使用print,eg:
awk '/Sally/{print "\t\tHave a nice day, " $1, $2 "!"}'
逗号,表示常量,变量间使用默认的OFS填充,引号中的就是常量,$1这些就是变量
复杂输出(格式化输出,跟c的printf一致)使用printf,eg:
awk '{printf "The name is %-15s ID is %8d\n", $1, $3}' employees
一些内置变量:
NF: Number of Fields 当前行字段数目
NR: Number of Records 当前行号
awk –F'[ :\t]'说明使用空格,制表,冒号作为字段分隔符
所有的正则都可以用,甚至&都可以,而且默认使用的是扩展正则表达式,即便是{}都可以加上--re-interval来实现
关系运算符:<, >, <=, >=, ==, !=, ~, !=. eg:
$3 > 100{print $3} 或者 100 < $3{print $3}
但是~和!~就不要这样弄了
条件表达式:
布尔表达式 ? 表达式1 : 表达式2
为真,该表达式值为表达式1,为假则反之,eg:
max = ($1 > $2) ? $1 : $2; print max
算术运算符:(按照浮点数来进行计算)
+, -, *, /, %, ^. eg:
$3 * $4 > 500
逻辑操作符:
&&, ||, !
复合模式:
$3 > 100 || $4 ~ /Nice/
范围模式:匹配从第一个模式首次出现(为真)到第二个模式的首次出现(为真)之间的内容(如是循环),第二个没发现,显示到最后。eg:
/Tom/, /Susan/
赋值运算符:
=, +=, %=等等。eg:
$3 == "Chris" { $3 = "Christian"; print} #若$3为指定字符串,将之改为需求字符串并打印该行
变量不用声明,自动初始化为0和空串,可以在数值和字符串间相互变化,变量名和C的要求相同:
=, +=, -=, *=, /=, %=, ^=, eg:
wage=$2*$3
递增,递减运算符:(性质和C相同)
++, --
命令行上用户自定义变量,eg:
awk –v month=11 –v year=2011 –f awkscropt filename
字段变量:$1, $2等等,可以修改,eg:
awk '{$5=1000*$3/$2; print}'
内置变量(linkhere)
BEGIN模式:在对输入文件进行任何处理前首先执行的操作
END模式:在对所有输入文件都进行处理过后执行的操作
输出重定向>:
awk 'print $1, $2 > "file"' filename
#将file(文件名)清空并打开(>的操作),将filename的1,2字段输出到file中
输入重定向getline:
awk 'BEGIN{"ls -l" | getline d; print d}' filename
#将ls –l输出的内容放到管道文件中,getline d完成将改管道的当前行放到d中的任务,注意这个d是可有可无的,有匿名变量保存getline的数据,并且print也会使用这个匿名变量的数据
管道|
awk的管道似乎和shell中的不同,它是在运行结束后再将管道用于后续的操作,eg:
print $1,$2 | "sort -n > testout" #会在所有行都跑完过后才进行sort
管道也可以打开很多条,不知道书中的每次只能打开一个管道是什么意思
print $1,$2 | "sort -n > testout"
print $1,$2 | "sort -k2 > testout2"
可以使用close("sort -n")来关闭管道,我觉得关闭管道就是为了刷新输出,表示已经提供好输入,可以供管道右侧的命令使用了
system()函数,跟c中的同名函数的使用一样的,eg:
system("sort -n " ARGV[2]">tempfile")
system("mv tempfile "ARGV[2])
条件语句if,同C一样,多条语句才需要花括号框住
if(表达式){
语句; 语句; …
}
if/else语句:
{if(表达式){
语句; 语句; …
}
else{
语句; 语句; …
}
}
if/else if/…/else语句:
{if(表达式){
语句;…
}
else if(表达式){
语句;…
}
else if(表达式){
语句;…
}
…
else{
语句;…
}
}
while循环,do/while循环,for循环,continue,break:
{i=1; while(i<=NF){print NF, $i; ++i}}
{i=1; while(i<=NF){if($i<0){print "continue"; continue} print NF, $i; ++i;}} #注意在块语句后面可以不使用分号分隔,跟sed不同哟
{for(x=3;x<=NF;++x)
if($x<0){print "break"; break}
}
next语句:停止本行操作,开始执行下一行的操作
exit语句:终止awk程序对文件的处理,不能跳过END,后跟awk返回值,eg:
exit (1)
数组(是个hashmap),使用时创建,使用[]索引:arrayname[key]
特殊for:
{for(key in arrayname)){
print arrayname[key]
}
}
多维数组:matrix[key1, key2] = matrix[key1 SUBSEP key2],其中(SUBSEP = \034)
命令行处理参数:
ARGV:从0开始,分别为awk命令,文件1……文件n
ARGC:ARGV的维数
由于awk会依次处理所有输入文件,因此可以在BEGIN中使用delete删除不需要的文件,eg:
BEGIN{print "ARGV[2]" is ARGV[2]}
{print}
字符串函数:
sub函数用于在目标串(默认为本记录)中查找能够匹配regex的最长且最靠左的子串,然后用替换串取代找到的子串。
gsub函数替换能够匹配regex的所有的子串
index函数返回子串在字符串中第一次出现的位置,偏移量从1开始计算,格式:
index(字符串, 子串)
length函数返回字符串(默认为当前记录)中字符的个数,格式:
length(字符串)
length
substr函数返回从字符串制定位置(偏移量从1开始计算)开始,指定长度(默认为到末尾,如果超过末尾,也只输出到末尾)的一个子串,格式:
substr(字符串, 起始位置)
substr(字符串,起始位置,子串长度)
match函数返回regex在字符串中出现的位置,如果未出现,则返回0。match函数把内置变量RSTART设为子串在字符串中的起始位置,RLENGTH则设置为子串长度,可配合substr使用,格式:
match(字符串, 正则表达式)
split函数使用第三个参数(默认为FS)指定的字段分隔符,把字符串拆分成一个数组,格式:
split(字符串, 数组, 字段分隔符)
split(字符串, 数组)
sprintf函数,类似C的sprintf,格式化后赋给一个变量,格式:
variable=sprintf("含有格式说明的字符串", 表达式1, 表达式2, …, 表达式n)
内置算术函数
int函数:舍去小数点后所有数字,生成一个整数
rand函数:生成[0, 1)的浮点数
srand函数:srand(x)把x设成种子,不提供参数则根据当前系统时间