推荐awk学习系列
https://www.ibm.com/developerworks/cn/linux/shell/awk/awk-1/index.html
https://www.ibm.com/developerworks/cn/linux/shell/awk/awk-2/index.html
https://www.ibm.com/developerworks/cn/linux/shell/awk/awk-3/index.html
工具书
https://book.saubcy.com/AwkInAction/section_1/chapter_2_1.html
1 调用awk方式
1.命令行方式
awk [-F field-separator] ‘commands’ input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
2 基本命令
2.1 行匹配语句 awk ” 只能用单引号
awk '{[pattern] action}' {filenames}
例
test.sh文件
将文件按照’\t’或者’ ‘分割,输出第一列和第四列的内容
#!/bin/bash
awk '{print $1,$4}'
执行
chmod +x test.sh
cat b | ./test.sh
结果 输出b文件中每行的第一列和第四列
2.2 指定分隔符关键字 -F
脚本文件
#!/bin/bash
awk -F, '{print $1,$4}'
指定分隔符为’,’
指定多个分隔符 -F ‘[]’
脚本文件
#!/bin/bash
awk -F '[\t,]' '{print $1}'
先按照’\t’切分,再按照’,’切分
2.3 设置变量
用awk -v
设置变量
脚本文件
#/bin/bash
awk -va=1 -vb=s '{print $1,$1+a,$1b}'
$1+a
是计算第一列与变量a的和,如果$1
为字符串,则只返回变量a的数值,$1b
是字符串拼接,将$1
与变量a的内容链接起来
2.4 筛选匹配
脚本文件
#/bin/bash
awk '$1>3 && ($3 == "d" || $3 == "e") { print $0 }'
类c模式,左边为条件,右边为满足条件的操作,这里是满足条件输出当前行
2.5 正则
# 输出第二列包含 "th",并打印第二列与第四列
$ awk '$2 ~ /th/ {print $2,$4}' log.txt
# 输出包含"re" 的行
$ awk '/re/ ' log.txt
# 忽略大小写
$ awk 'BEGIN{IGNORECASE=1} /this/' log.txt
# 模式取反
$ awk '$2 !~ /th/ {print $2,$4}' log.txt
$cat a
1.021 33
1#.ll 44
2.53 6
ss 7
awk 'BEGIN{total = 0;len = 0} {if($1~/^[0-9]+\.[0-9]*/){total += $1; len++}} END{print total/len}' a
$1~/^[0-9]+\.[0-9]*/表示$1与“/ /”里面的正则表达式进行匹配,若匹配,则total加上$1,且len自增,即数目加1.“^[0-9]+\.[0-9]*”是个正则表达式,“^[0-9]”表示以数字开头,“\.”是转义的意思,表示“.”为小数点的意思。“[0-9]*”表示0个或多个数字
3 awk脚本
关于awk脚本,有两个关键词BEGIN和END。
- BEGIN{ 这里面放的是执行前的语句 }
- END {这里面放的是处理完所有的行后要执行的语句 }
- {这里面放的是处理每一行时要执行的语句}
文件
$ cat score.txt
Marry 2143 78 84 77
Jack 2321 66 78 45
Tom 2122 48 77 71
Mike 2537 87 97 95
Bob 2415 40 57 62
awk脚本
$ cat cal.awk
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
执行
awk -f cal.awd score
结果
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
4 其他
awk、sed、grep更适合的方向:
- grep 更适合单纯的查找或匹配文本
- sed 更适合编辑匹配到的文本
- awk 更适合格式化文本,对文本进行较复杂格式处理
关于awk内建变量
- 解释一下变量:
- 变量:分为内置变量和自定义变量;输入分隔符FS和输出分隔符OFS都属于内置变量。
内置变量就是awk预定义好的、内置在awk内部的变量,而自定义变量就是用户定义的变量。
FS:输入字段分隔符, 默认为空白字符
OFS:输出字段分隔符, 默认为空白字符
RS:输入记录分隔符(输入换行符), 指定输入时的换行符
ORS:输出记录分隔符(输出换行符),输出时用指定符号代替换行符
NF:当前行的字段的个数(即当前行被分割成了几列)
NR:行号,当前处理的文本行的行号。
FNR:各文件分别计数的行号
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数
自定义变量的方法
方法一:-v varname=value ,变量名区分字符大小写。
引用 http://www.runoob.com/linux/linux-comm-awk.html
5 笔记
- 执行awk脚本传参
awk -f test.awk a="test" filename #入参a,数据类型为string
awk -f test.awk a=1 filename #入参a,数据类型为数字
# 在脚本呢中直接用a访问
- awk脚本中的数组
#awk 遇到第一个赋值语句时,它将创建 myarray
myarray[1]="jim"
myarray[2]=456
#遍历数组
for ( x in myarray ) {
print myarray[x]
}
注意:每次赋值以后都循环一次循环代码。虽然这是一个非常方便的 awk 功能,但它有一个缺点 – 当 awk 在数组下标之间轮转时,它不会依照任何特定的顺序。
所以输出可能是
jim
456
也可能是
456
jim
awk的性质: 数组下标字符串化
所以awk可以当作map来使用
myarr["name"]="Mr. Whipple"
print myarr["name"]
同样的
可以判断key是否在array中
if ( 1 in fooarray ) {
print "Ayep! It's there."
} else {
print "Nope! Can't find it."
}
删除元素的操作
delete fooarray[1]