awk 的使用

AWK是贝尔实验室1977年搞出来的文本出现神器。

awk是一种用于处理文本、模式匹配的编程语言。与sed和grep,俗称Linux下的三剑客。相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。

要学AWK,就得提一提AWK的一本相当经典的书《The AWK Programming Language》,它在豆瓣上的评分是9.4分!

基础用法

格式:awk 执行的事件 文件

root@xiaocan:~# awk '{print $0}' test.txt
My first language:Python
My second language:Shell
My third language:Java
My fourth language:C

其中,print 表示打印,$0 表示一整个记录,test.txt 表示一个文件。所以

awk '{print $0}' test.txt

表示把 test.txt 文件里面的每行记录都打印出来。

# $0 表示整个记录,不过 $1, $2, $3.....则表示整个记录中的第一个字段,第二个字段......。
root@xiaocan:~# awk '{print $1}' test.txt
My
My
My
My
root@xiaocan:~# awk '{print $2}' test.txt
first
second
third
fourth
root@xiaocan:~# awk '{print $3}' test.txt
language:Python
language:Shell
language:Java
language:C

下面我们用 : 来作为我们的分隔符吧。

root@xiaocan:~# awk 'BEGIN{FS=":"} {print $2}' text.txt

上面的命令等价于:

root@xiaocan:~#  awk -F ':' '{print $2}' test.txt
Python
Shell
Java
C

上面我们用参数 -F 指定了分隔符。

可以指定多个分隔符:

awk -F '[;:]'

我们再来看看 awk 的格式化输出,和 C 语言的 printf 没什么两样:

root@xiaocan:~# awk -F: '{printf "%-20s -- %s\n",$1,$2}' awkTest.txt
My first language    -- Python
My second language   -- Shell
My third language    -- Java
My fourth language   -- C

条件限制

# 打印第二个字段为"Java"的文本
root@xiaocan:~# awk -F ':' '$2 == "Java" {print $2}' test.txt
Java

#打印奇数行的的第二个字段:
root@xiaocan:~# awk -F ':' 'NR % 2 == 1 {print $2}' test.txt
Python
Java
#或者
root@xiaocan:~# awk -F ':' 'NR % 2 == 1' test.txt
My first language:Java
My third language:python

其中,NR 是一个内置的变量,表示当前正在处理的记录,即当前的记录是第几个记录。

其中的“==”为比较运算符。其他比较运算符:!=, >, <, >=, <=

字符串匹配

# 匹配第三列有 Java 的行
root@xiaocan:~# awk '$3 ~ /Java/' test.txt
My first language:Java

~ 表示模式开始。/ /中是模式。这就是一个正则表达式的匹配。

其实 awk 可以像 grep 一样的去匹配第一行,就像这样:

root@xiaocan:~# awk '/Java/' test.txt
My first language:Java
root@xiaocan:~# awk '/Java|Python/' test.txt
My first language:Python
My third language:Java

模式取反:

root@xiaocan:~# awk '!/Java/' test.txt
My first language:Python
My second language:Shell
My fourth language:C

更多正则表达式匹配,参看这篇文章

拆分文件

awk拆分文件很简单,使用重定向符号 > 就好了。下面这个例子,是按第 2 列分隔文件,相当的简单。

$ awk '{print > $2}' test.txt
 
$ ls
C Java Python Shell

条件语句

和我们平常的编程一样,awk 也提供了 if, else, while 等这些条件语句。

例如,打印第二个及其之后的记录:

root@xiaocan:~# awk '{if(NR > 1) print $2}' test.txt
second
third
fourth
# 或者
root@xiaocan:~# awk 'NR > 1 {print $2}' test.txt

注意,上面的字段分隔符是空格了,并且 if 语句是在“{}” 里指定的。

root@xiaocan:~# awk '{if($1 < "s") print $1; else print $2}' test.txt
# 如果第一个字段小于“s",则打印第一个字段,否则打印第二个字段
My
My
My
My

函数

awk 提供了一些内置函数来供我们使用,一下常用的函数如下:

tolower():字符转为小写。
toupper():字符转为大写
length():返回字符串长度。
substr():返回子字符串。
sqrt():平方根。
rand():随机数

root@xiaocan:~# awk '{print toupper($1)}' test.txt
MY
MY
MY
MY
root@xiaocan:~# awk '{print tolower($1)}' test.txt
my
my
my
my
root@xiaocan:~# awk -F ':' '{print toupper($2)}' test.txt
PYTHON
SHELL
JAVA
C
root@xiaocan:~# awk -F ':' '{print tolower($2)}' test.txt
python
shell
java
c

变量

常用的内置变量如下:

$0当前记录(这个变量中存放着整个行的内容)

$1~$n 当前记录的第n个字段,字段间由FS分隔

NR:表示当前处理的是第几行

NF:表示当前行有多少个字段

FNR 当前文件的行数

FILENAME:当前文件名

FS:字段分隔符,默认是空格和制表符。

RS:行分隔符,用于分割每一行,默认是换行符。

OFS:输出字段的分隔符,用于打印时分隔字段,默认为空格。

ORS:输出记录的分隔符,用于打印时分隔记录,默认为换行符。

OFMT:数字输出的格式,默认为%.6g

例如我们要打印每一个记录的最后一个字段,就可以使用变量 NF 了。

root@xiaocan:~# awk '{print $NF}' test.txt
language:Python
language:Shell
language:Java
language:C

# 倒数第二个字段
root@xiaocan:~# awk '{print $(NF-1)}' test.txt
first
second
third
fourth

对了,刚才那个 NR 的变量也是挺好用的,例如:

root@xiaocan:~# awk '{print NR ". "  $0}' test.txt
1. My first language:Python
2. My second language:Shell
3. My third language:Java
4. My fourth language:C

awk 脚本

awk 的语法如下:

  • 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
}

我们来看一下执行结果:(也可以这样运行 ./cal.awk score.txt

$ awk -f cal.awk score.txt
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

统计

统计某个文件夹下的文件占用的字节数

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
[end]size is  8657198

如果以M为单位显示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}' 
[end]size is  8.25889 M

注意,统计不包括文件夹的子目录。

环境变量

即然说到了脚本,我们来看看怎么和环境变量交互:(使用-v参数和ENVIRON,使用ENVIRON的环境变量需要export)

$ x=5
 
$ y=10
$ export y
 
$ echo $x $y
5 10
 
$ awk -v val=$x '{print $1, $2, $3, $4+val, $5+ENVIRON["y"]}' OFS="\t" score.txt
Marry   2143    78      89      87
Jack    2321    66      83      55
Tom     2122    48      82      81
Mike    2537    87      102     105
Bob     2415    40      62      72

最后,我们再来看几个小例子:

#从file文件中找出长度大于80的行
awk 'length>80' file

#打印99乘法表
seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'

关于其中的一些知识点可以参看gawk的手册

参考

  1. AWK 简明教程:https://coolshell.cn/articles/9070.html
  2. https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_72/com.ibm.aix.cmds1/awk.htm
  3. http://man.linuxde.net/awk
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值