linux命令学习(三)——awk

2017-05-20  本文已影响184人  陌上疏影凉

学习资料:《linux大棚命令百篇上》

awk介绍及简单实用

以下是在网上找到的两个awk的介绍:

awk的命令格式和选项

格式awk [Options] 'Pattern {Actioin}' filename
说明

  1. Option部分,用来指定命令选项
  2. Pattern部分,用来指定判断条件,相当于我们之前说sed的行匹配语句。
  3. Action部分,用于指定awk的动作,也就是对Pattern选中行执行的操作。
  4. filename部分,用于指定awk要操作的文件名

举个栗子

通过以下awk命令可以将一个文件全部输出,效果同cat student

wangsheng@ubuntu[14:44:40]:~/Documents$ awk '{print $0}' student 
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

也可以输出第1列和第3列

wangsheng@ubuntu[14:45:04]:~/Documents$ awk '{print $1,$3}' student 
Marry 78
Jack 66
Tom 48
Mike 87
Bob 40

awk的工作原理

来自: http://man.linuxde.net/awk
(以下摘抄自《linux大棚命令百篇》)

  1. awk读取一条记录(文件中一行内容)作为输入,并将这条记录赋值给内部变量$0。
  2. 记录被分符分割成多个字段,每一个字段都存储到指定编号的变量中,从$1开始。(awk内部变量FS用来指定字段的分隔符,默认情况下为空格)
  3. 对于每一条记录,按照规定的pattern进行匹配,如果匹配成功,则执行对应的action,否则不执行。pattern和action都是可选的,但两者必须提供一个。
    • 如果未指定pattern,则对所有行都执行action操作。
    • 如果未指定action,则对指定行执行{print}操作,打印匹配行的内容。
    • 如果action指定为{},则不做任何操作。

awk的各个组成部分详解

option

options用来指定awk的选项,到底有哪些选项呢?我们一个一个来看看

# 文件内容
wangsheng@ubuntu[14:53:33]:~/Documents$ cat log 
hello,world,java,linux,android
# 不使用-F
wangsheng@ubuntu[14:51:51]:~/Documents$ awk '{print $1,$3}' log 
hello,world,java,linux,android 
# 使用-F
wangsheng@ubuntu[14:52:19]:~/Documents$ awk -F , '{print $1,$3}' log 
hello java
# 定义一个变量并输出a+文件内容
wangsheng@ubuntu[14:57:27]:~/Documents$ awk -v a=1 '{print a$0}' log 
1hello,world,java,linux,android
# 定义两个变量时,每个变量前加—v
wangsheng@ubuntu[14:58:10]:~/Documents$ awk -v a=1000 -v b=2000 '{print a$0b}' log 
1000hello,world,java,linux,android2000

pattern

说完了选项,我们来说说这个pattern,它也是可选的,表示匹配哪一行。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。pattern可以包含如下几项:

# 打印含有Jack的行
wangsheng@ubuntu[15:14:16]:~/Documents$ awk '/Jack/ {print}' student 
Jack    2321 66 78 45
# NR是awk的一个内置变量,代表行号
# 用NR%2==0这个关系表达式这个模式
#   当结果为true时,执行{next}
#   当结果为false时,执行{print NR,$0},将行号与该行内容输出
wangsheng@ubuntu[15:14:50]:~/Documents$ awk 'NR%2==0 {next} {print NR,$0}' student 
1 Marry   2143 78 84 77
3 Tom     2122 48 77 71
5 Bob     2415 40 57 62
# 选取第1列(名字)中不含有o的那些行,打印该行内容
wangsheng@ubuntu[15:25:35]:~/Documents$ awk '$1 !~ /o/ {print}' student 
Marry   2143 78 84 77
Jack    2321 66 78 45
Mike    2537 87 97 95
# 选取第1列中含有o的那些行,打印该行内容
wangsheng@ubuntu[15:26:45]:~/Documents$ awk '$1 ~ /o/ {print}' student 
Tom     2122 48 77 71
Bob     2415 40 57 62
  • BEGIN语句块:可选的语句块,在awk开始从输入流中读取行之前被执行,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
  • pattern语句块:可选的语句块,是最重要的部分。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
  • END语句块:可选的语句块,在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成。

action

常用的action当然就是print了,当然在这个action中我们能做很多事情,完全就跟用c语言编程一样,可以有条件控制、循环、赋值、数组定义使用等等,这里就不展开来说了。具体用法可以参见http://man.linuxde.net/awk。 这里要重点说一下的是awk的内置变量。

awk的内置变量

所谓内置变量就是指awk中自带的变量,不需要用-v来定义就可以使用的变量。常用的有以下几种:

wangsheng@ubuntu[16:16:20]:~/Documents$ awk '{print ARGC}' log
2
wangsheng@ubuntu[16:17:04]:~/Documents$ awk '{print ARGV[0]}' log
awk
wangsheng@ubuntu[16:18:35]:~/Documents$ awk '{print ARGV[1]}' log
log
wangsheng@ubuntu[16:01:23]:~/Documents$ awk '{print FILENAME}' log 
log
wangsheng@ubuntu[21:58:04]:~/Documents$ awk '{print FILENAME}' log student 
log
student
student
student
student
student
wangsheng@ubuntu[16:02:05]:~/Documents$ awk -F , '{print FS}' log
,
wangsheng@ubuntu[22:02:02]:~/Documents$ awk -F , 'BEGIN{OFS="-"} {print $1,$2,$3}' log
hello-world-java
wangsheng@ubuntu[22:02:11]:~/Documents$ awk '{print NR}' log student 
1
2
3
4
5
6
wangsheng@ubuntu[22:03:24]:~/Documents$ awk '{print FNR}' log student 
1
1
2
3
4
5

处理多个文件

  1. 当要处理两个文件的时候,如何判断当前操作的是哪个文件呢?其实看了之前awk的内置变量,答案并不是很难,直接通过FNR与NR的关系就可以了。当操作的是第一个文件的时候,FNR==NR;当操作的是第二个文件的时候,FNR<NR。
wangsheng@ubuntu[22:03:46]:~/Documents$ awk 'FNR==NR {print "this is first file"} FNR<NR {print "this is second file"}' log student 
this is first file
this is second file
this is second file
this is second file
this is second file
this is second file
  1. 当要处理的有三个文件的时候怎么办呢?上面这个办法显然不能解决问题,它只能判断是否是第一个文件,所以当判断三个或三个以上的文件的时候,可以使用FILENAME与ARGS数组,当FILENAME==ARGV[1]时,代表当前操作的是第一个文件,FILENAME==ARGV[2]的时候是第二个以此类推。
wangsheng@ubuntu[22:17:21]:~/Documents$ awk 'FILENAME==ARGV[1] {print "1--"} FILENAME==ARGV[2] {print "2----"} FILENAME==ARGV[3] {print "3---"}' log student hello
1--
2----
2----
2----
2----
2----
3---
3---

awk脚本

还记得我们之前说awk -f选项的作用吗?看之前的代码也能看出来,awk的中间部分是很长的,如果每次都在命令行敲难免有些麻烦,将其放在文件中保存,使用的时候直接调用文件名,这样就很方便了,-f选项就是代表我写的awk中间的pattern {action}部分在后面的脚本文件中。
首先创建一个awk脚本文件script.awk,注意文件开头是#!/bin/awk -f

#!/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
}

脚本在BEGIN部分给三个变量赋值,接着打印一个表头;中间对每行进行累加第3、4、5列数值的操作;END部分将最终处理的值打印出来。
运行脚本:

//源文件
wangsheng@ubuntu[22:30:01]:~/Documents$ cat student 
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
//运行后的结果
wangsheng@ubuntu[22:30:03]:~/Documents$ awk -f script.awk student 
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

格式化输出

格式化输出用于将数据按照我们想要的格式进行输出,而不是直接将数据打印出来。

格式 描述
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法

看几个例子:

wangsheng@ubuntu[22:55:50]:~/Documents$ awk 'BEGIN{a=124.113;printf("%-10.2f",a)}'
124.11    wangsheng@ubuntu[22:55:55]:~/Documents$

%-10.2f f表示浮点数,.2表示小数部分保留两位,10表示总共占10个空白字符空间,-表示左对齐

wangsheng@ubuntu[22:59:24]:~/Documents$ awk 'BEGIN{a=90;printf("%10X",a)}'
        5Awangsheng@ubuntu[22:59:31]:~/Documents$ 

%10X X表示转为十六进制数,10表示总共占10个空白字符长度

wangsheng@ubuntu[23:03:33]:~/Documents$ cat log 
hello,world,java,linux,android
wangsheng@ubuntu[23:03:35]:~/Documents$ awk -F , '{printf("%-10s---%10s---%-10s---%10s",$1,$2,$3,$4)}' log
hello     ---     world---java      ---     linuxwangsheng@ubuntu[23:03:38]:~/Documents$ 

将log文件根据,分割开,分别对第1、2、3、4列打印输出,有的左对齐,有的右对齐,均占10个空白字符

参考资料

http://man.linuxde.net/awk
http://www.runoob.com/linux/linux-comm-awk.html
http://www.mamicode.com/info-detail-1594530.html

上一篇 下一篇

猜你喜欢

热点阅读