awk
linux三剑客之一,对复杂的文本进行处理,不直接编辑源文件,需要重定向才能保存
内置变量
ARGC 命令行参数个数
ARGV 数组,保存的是命令行所给定的个参数
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 各文件分别计数的行号
FS 设置输入域分隔符,等价于命令行 -F选项,默认分割符为空格或tab键
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
$0 变量是指整条记录,$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
$NF 是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数
BEGIN 在awk读取输入之前执行的代码块
END 结尾代码块,对所有行进行处理后再执行的代码块,用于输出结尾信息
常用符号和通配符
数学运算:+,-,*,/, %,++,- -
逻辑关系符:&&, ||, !
比较操作符:>,<,>=,!=,<=,== ~ !~
文本数据表达式:== (精确匹配)
~ 波浪号表示匹配后面的模式
^ 行首定位符 /^my/ 匹配所有以my开头的行
$ 行尾定位符 /my$/ 匹配所有以my结尾的行
. 匹配除换行符以外的单个字符 /m..y/ 匹配包含字母m,后跟两个任意字符,再跟字母y的行
* 匹配零个或多个前导字符 /my*/ 匹配包含字母m,后跟零个或多个y字母的行
[] 匹配指定字符组内的任一字符 /[Mm]y/ 匹配包含My或my的行
[^] 匹配不在指定字符组内的任一字符 /[^Mm]y/ 匹配包含y,但y之前的那个字符不是M或m的行
& 保存查找串以便在替换串中引用 s/my/**&**/ 符号&代表查找串。my将被替换为**my**
\< 词首定位符 /\<my/ 匹配包含以my开头的单词的行
\> 词尾定位符 /my\>/ 匹配包含以my结尾的单词的行
x\{m\} 连续m个x /9\{5\}/ 匹配包含连续5个9的行
\{m,\} 至少m个x /9\{5,\}/ 匹配包含至少连续5个9的行
x\{m,n\} 至少m个,但不超过n个x /9\{5,7\}/ 匹配包含连续5到7个9的行
参数的使用实例
awk '{print}' /etc/passwd #输出所有域
awk '{print $0}' /etc/passwd #同上
awk '/root/' /etc/passwd #输出含关键字的所有行
awk '{2=="**";print $0}' test.txt #默认分割符,将第二域的值替换为**,整体输出
-f 指定脚本
awk -f script.awk test.txt
-F 指定分割符
awk -F: '{print $1; print $2}' /etc/passwd #将每一行的前二个字段,分行输出
awk -F":" '{print $1,$3}' /etc/passwd #多了一个逗号,$1与$3使用空格分隔
awk -F: '/root/ {print $7}' /etc/passwd #输出含关键字的行的对应域
awk -F: 'NR==5{print}' /etc/passwd #显示第5行
awk -F":" '!/yozo/ {print $2,$4}' /etc/passwd #去除匹配行
awk 'NR!=1{print}' /etc/passwd #不显示第一行
awk -F: '{print $1,$3,$4}' OFS="\t" /etc/passwd #输出字段1,3,6,以制表符作为分隔符
awk -F':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:" $0}' /etc/passwd
#统计/etc/passwd文件名,每行行号,每行列数,对应的完整行内容
awk -F: '{printf ("filename:%10s,linenumber:%3s,column:%3s,content:%3f\n",FILENAME,NR,NF,$0)}' /etc/passwd
#使用printf代替print
awk -F: 'NR==2{print "filename:" FILENAME,$0}' /etc/passwd #打印第二行信息
awk -F":" '{print $NF-1}' /etc/passwd #指定分隔符,查找倒数第二列
awk -F "[/]" 'NR == 4 {print $0,"\n",$1}' /etc/passwd #这里以/为分隔符,多个分隔符利用[]然后在里面写分隔符即可
awk -F '[/:]' '{print $2}' /etc/passwd #先使用/进行分隔,在使用:分隔,取指定域
cat /etc/passwd | awk -F: 'BEGIN{print "name, shell"} {print $1,$NF} END{print "hello world"}'
#添加BEGIN和END
awk '$2 ~ /root/ {print $2,$3}' /etc/passwd #输出第二列包含"th",输出指定域
awk 'BEGIN{IGNORECASE=1} /mysql/' /etc/passwd #忽略大小写
awk '$2 !~ /th/ {print $2,$4}' /etc/passwd #模式取反
-v 定义变量
awk -v action="success" 'BEGIN{print action}' #自定义变量
awk -v lang=$LANG 'BEGIN {print lang}' #引用全局变量
IF语句
必须用在{}中,且比较内容用()扩起来
awk -F: '{if($1~/mail/) print $1}' /etc/passwd #简写
awk -F: '{if($1~/mail/) {print $1}}' /etc/passwd #全写
awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd #if...else...
awk -F":" '{if(NR>20 && NR<25) print $1}' /etc/passwd #获取第20-25行的第一列信息
awk字符串函数
length()
index()
gensub()
gsub()
sub()
substr()
match()
split()
tolower()
toupper()
length([string]) #字符串长度
awk '{print length()}' test.txt #返回每一行的字符数
index(in,find) #在字符串in中查找find的第一个匹配项,返回其位置下标,没有匹配项返回0
awk 'BEGIN {print index("hello","lo")}'
gensub(regexp,replacement,how[,target]) #将匹配的值进行替换,how取值为g或G的字符串,默认不指定target值则表示$0
gawk '
BEGIN {
a="abcd bef"
b=gensub("b","B",1,a) #将b替换为B,1表示默认分隔符的第一域,a为操作对象
print b}'
gawk 'BEGIN {a="abcd bef";b=gensub("b","B",1,a);print b}'
gawk '
BEGIN {
a="abcd bef"
b=gensub(/(.+) (.+)/,"\\2 \\1","g",a)
print b }'
gawk 'BEGIN {a="abcd bed"; b=gensub(/(.+) (.+)/,"\\2 \\1","g",a); print b}'
gsub(regexp,replacement[,target]) #gsub中的g表示global,全局
echo "hello,good,hello,good" | awk {' gsub(/hello/, "Hi"); print '} #将所有匹配的字符串进行替换
sub(regexp,replacement [,target]) #从左边开始匹配,替换第一个匹配值
awk 'BEGIN {str="why why study";sub(/why/,"no",str);print str}' #target为变量,不指定默认取$0
substr(string,start [,length]) #返回string中指定位置和长度的子字符串,长度大于结尾长度取到结尾
awk 'BEGIN {s=substr("helloworld",3,4);print s}'
match(string,regexp [,array]) #匹配子字符串
echo "heellowoorld" | gawk '{match($0,/(he+).+(wo+)/,arr) ; print arr[1] arr[2] }'
split(string,array [,fieldsep [,seps]]) #将字符串string由fieldsep分隔符分隔,字符串片段存储在array,分隔符存储在seps
awk 'BEGIN {split("he-ll-o",a,"-",seps); print a[1],a[2],a[3],seps[1],seps[2]}'
awk 'BEGIN {n=split("he-ll-o",a,"-",seps); print n}' #返回值为数组的元素个数
tolower(string) #将字符串中的所有大写字母转为小写
awk 'BEGIN {s=tolower("HellO WoRld");print s}'
toupper(string) #将字符串中的所有小写字母转为大写
awk 'BEGIN {s=toupper("HellO WoRld");print s}'
综合:
#FS读取时列分割符,OFS输出时列分割符,第一域上匹配root字符串用toor替换,输出所有匹配的域
awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"toor",$1) {print $0}' test.txt
#替换所有域匹配的字符串,全部输出
awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"ssss") {print $0}' test.txt
awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"ssss",$0) {print $0}' test.txt
#区分大小写,输出"fafae"匹配字符d的位置
awk 'BEGIN {print match("fdfae",/d/)}'
#IGNORECASE变量值为1使得匹配区分大小写
awk 'BEGIN {IGNORECASE=1;print match("sGgGfff",/g/)}'