shell文本过滤编程(四):awk内置变量及一般变量

【版权声明:转载请保留出处:blog.csdn.net/gentleliu。Mail:shallnew at 163 dot com】

awk有许多内置变量用来设置环境信息。这些变量可以被改变。下面是awk内置变量:
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME  a w k浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 - F选项
NF 浏览记录的域个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
 
1、     内置变量
NF支持记录域个数,在记录被读之后再设置,也就是读入的每一行根据设置的分割符号分割出来的域的个数。也叫做“字段数量”变量。awk 会自动将该变量设置成当前行中的字段数量。
NR查看当前正在操作的行号。
FILENAME 记录当前正在操作文件的文件名。
现在我们取出文件group_file1的行号以及每一行域数量。
awk '{print NR, NF}' group_file1    
1 3
2 3
3 3
4 4
5 3
现在我们传入awk两个文件,去除当前操作的文件名以及NR、NF信息:
# awk '{print FILENAME,NR, NF}' group_file1 group_file2
group_file1 1 3
group_file1 2 3
group_file1 3 3
group_file1 4 4
group_file1 5 3
group_file2 6 1
group_file2 7 1
group_file2 8 1
group_file2 9 1
group_file2 10 1
可见NR并非当前行在文件中的行号,而是整个被操作文件列表被操作的行数量,没处理一行该值会加一。
有了NF、NR之后我们的操作又变得更加灵活了。我们可以再加入条件判断和正则表达式,下面打印字段数量为3并且第三字段匹配98的行:
# awk '{if (NF == 3 && $3~/98/) print}' group_file1
wireshark x 987
usbmon x 986
jackuser x 985
我们可以将当前绝对路径传入,分析出当前目录名称:
# pwd
/home/Myprojects/shell_text_filter/awk
# pwd | awk -F"/" '{print $NF }'
awk
类似地,传入文件绝对路径,也可以分析出文件名。
OFS 可以使打印的单字段之间打印 OFS 变量,我们可以方便地重新定义 OFS,这样 awk 将插入我们中意的字段分隔符。没有设置OFS,默认为空。
# awk 'BEGIN{OFS=" - "}{print $1, $3}'  group_file1  
wireshark - 987
usbmon - 986
jackuser - 985
vboxusers - 984
aln – 1001
ORS输出记录分隔符,通过设置缺省为换行("\n") 的 OFS,我们可以控制在 print 语句结尾自动打印的字符,缺省 ORS 值会使 awk 在新行中输出每个新的 print 语句。如果想使输出的间隔翻倍,可以将 ORS 设置成 "\n\n"。或者,如果想要用单个空格分隔记录(而不换行),将 ORS 设置成 " "。比如如下两个文件:
# cat 1
1 2 3 4 5
# cat 2
6 7 8 9 0
我们想将其内容连接到一行,可以这样使用:
# awk 'BEGIN{ORS=" "}{print}' 1 2
1 2 3 4 5 6 7 8 9 0
下面将group_file1文件每行用符号”-”链接在一起,:
# awk 'BEGIN{ORS=" - "}{print}END{ORS="\n";print "\n"}' group_file1
wireshark x 987  - usbmon x 986  - jackuser x 985  - vboxusers x 984 allen - aln x 1001  -
RS变量控制记录分隔符,通过RS 变量告诉 awk 当前记录什么时候结束,新记录什么时候开始。我们可以将一行记录通过设置RS变量将其分成多行记录来分析。比如我们将上面一条awk命令执行结果哪一行传入新的awk,通过设置RS将其分割成多行来分析:
# awk 'BEGIN{ORS=" - "}{print}END{ORS="\n";print "\n"}' group_file1 | awk 'BEGIN{RS=" - "}{print $1}'
wireshark
usbmon
jackuser
vboxusers
aln
2、    一般变量
在awk中,设置有意义的域名是一种好习惯一般的变量名设置方式为 var = $n,这里var    为调用的域变量名, n为实际域号。
# awk '{name=$1;id=$3;if (id==985)print name}' group_file1
jackuser
#
通常在BEGIN部分赋值是很有益的,可以在awk表达式进行改动时减少很多麻烦。比如我们想打印id大于1000的用户组名:
# awk 'BEGIN{id=1000}{if($3>id)print $1}' group_file1   
Aln
awk通过设置数据字段值并输出实现修改文件数据字段,当在awk中修改任何数据字段时,实际输入文件是不可修改的,修改的只是保存在缓存里的awk复本。如果我们修改原文件时,需要awk将修改后的内容输出到文件,然后在重命名为原文件。
# awk '{if($1=="aln")$3=$3-1; print $1,$2,$3}' group_file1      
wireshark x 987
usbmon x 986
jackuser x 985
vboxusers x 984
aln x 1000
同样,增加、减少、修改字段均可以有同样的操作。
Awk对每行数值进行统计得出结果很方便:
# awk 'BEGIN{total=0}{total+=$3}END{print "total="total}' group_file1            
total=4943
通过上面这个例子,我们想到可以写一个脚本来实现统计当前文件下面所有文件的大小之和,下面就是这样一个脚本:
#!/bin/sh

ls -al | awk '
BEGIN {
    total=0
}
{
    if (/^[^d]/) { #不统计目录
        total += $5
        print $1"\t"$5                                                                                                                                 
    }
}
END {
    print "total size: " total
}'

你可能感兴趣的:(shell文本过滤编程系列)