AWK 入门

作者: AlgoPeek | 来源:发表于2019-06-17 17:25 被阅读1次

AWK是一种处理文本文件的语言,也是一个强大的文本分析工具。AWK最早是在1977年在贝尔实验室被发明的,之所以叫AWK是因为其取了三位创始人 Alfred AhoPeter Weinberger, 和 Brian Kernighan 的Family Name的首字符。

本文不会详细讲述AWK的具体语法,如果有兴趣可以去看看《The AWK Programming Language》。本文只介绍AWK的基础知识及其常用的用法。

1. AWK的执行流程

1.1 执行流程

如果想要更灵活的运用AWK,首先需要知道AWK的工作流程,如下图:


AWK的工作流程是从输入流(文件、标准输入)中读一行,执行AWK命令,循环执行上述步骤直到文件结束。

1.2 AWK程序结构

AWK的程序结构主要包括三个部分:BEGIN块BODY块END块

1.2.1 BEGIN块

语法:

BEGIN {awk-commands}

BEGIN块是在AWK程序启动的时候执行,且只执行一次,BEGIN关键字是必须大写,经常用于输出头信息或初始化变量。该块是可选的。

shell> awk 'BEGIN{print "hello world";}'
hello world

1.2.2 BODY块

语法:

/pattern/ {awk-commands}

BODY块对每行输入执行一次,/pattern/是正则表达式,可以用于过滤行,是可选的,对于BODY块,没有关键字。

shell> cat marks.txt
1) Amit     Physics   80
2) Rahul    Maths     90
3) Shyam    Biology   87
4) Kedar    English   85
5) Hari     History   89
shell> awk '/a/ {print}' marks.txt
2) Rahul    Maths     90
3) Shyam    Biology   87
4) Kedar    English   85
5) Hari     History   89

1.2.3 END块

语法:

END {awk-commands}

END块在程序最后执行,且只执行一次,关键END是必须大写,该块经常用作尾信息或结果的输出。该块是可选的。

shell> echo -e "" | awk 'END{print "end of awk";}'
end of awk

1.3 AWK的基本语法

awk [options] -f program-file file ...
awk [options] program-text file ...

通常awk命令用文本表示,例如:

shell> awk '{print}' marks.txt

也可以将awk命令文本放到文件中,用-f参数指定,如:

shell> cat cmd.awk
{print}
shell> awk -f cmd.awk marks.txt

更多options可以通过awk --help查看,用的比较多的是-v-F,分别表示赋值和区域分隔符,如

shell> awk -v name="Jerry" 'BEGIN{print "hello" name}'
hello Jerry
shell> awk -F ":" '{print $1}' /etc/passwd | head -n 3
root
bin
daemon

2. 变量

AWK提供了丰富的内建变量,除了内建变量化,也允许用户自定义变量。

2.1 内建变量

前面提到的了变量$1就是内建变量,表示分隔符分隔的第一列值,仍然是marks.txt为例:

shell> cat marks.txt
1) Amit     Physics   80
2) Rahul    Maths     90
3) Shyam    Biology   87
4) Kedar    English   85
5) Hari     History   89

我们要输出第二列和第四列的值,如下:

shell> awk '{print $2, $4;}' marks.txt
Amit 80
Rahul 90
Shyam 87
Kedar 85
Hari 89

n表示第n列的值(n>=1),其中0表示整行,更多常用内建变量如下:

内建变量 说明
FS 输入域分隔符(Field Seperator),默认是空格,该内建变量同参数-F
RS 输入记录分隔符(Record Seperator),默认是换行
OFS 输出域分隔符(Output Field Seperator),默认是空格
ORS 输出记录分隔符(Output Record Seperator),默认是换行
NF 当前记录中域的数目
NR 当前记录所处的数目
FNR 同NR,但是相对于当前文件,当AWK处理多个文件时,该变量特别有用
FILENAME 当前文件名

更多内建变量参考AWK - Built-in Variables,再来看一个使用内建变量的例子:

echo -e "key1:val1\nkey2:val2" | awk 'BEGIN{FS=":"; OFS="=>"} {print "line " NR ": " $1, $2}'
line 1: key1=>val1
line 2: key2=>val2

2.2 自定义变量

除了前面提到的使用-v参数自定义变量外,我们还可以直接在块中自定义变量,变量定义直接用等号赋值,获取变量值直接引用就可以了。看个例子就明白了:

shell> cat sum.txt
124 127 130
112 142 135
175 158 245

如果我们要计算每一列的和以及平均数,利用awk可以很容易做到:

shell> awk '{sum=$1+$2+$3; average=sum/NF; print "Sum:", sum, "\t", "Average:", average}' sum.txt
Sum: 381     Average: 127
Sum: 389     Average: 129.667
Sum: 578     Average: 192.667

3. 操作符

awk支持丰富的操作符,和C语言非常类似,归纳起来如下:

操作符类型 操作符
算术操作符 +-*%^
自增自减操作符 前置++,前置--,后置++,后置--
赋值操作符 =+=-=*=/=%=^=**=
关系运算符 ==!=<<=>>=
逻辑运行符 &&,` !`
三目运算符 condition expression ? statement1 : statement2
一元运算符 +-
字符串拼接 字符串使用空格进行拼接,如awk 'BEGIN { str1 = "Hello, "; str2 = "World"; str3 = str1 str2; print str3 }',输出Hello, World
正则表达式操作符 使用~表示匹配,!~表示不匹配

这里跟C语言有点区别的是字符串拼接和正则表达式操作符,看下面例子:

#字符串拼接
shell> awk 'BEGIN{str1 = "Hello, "; str2 = "World"; str3 = str1 str2; print str3}'
Hello, World
#正则表达式匹配
shell> awk '$0 !~ 9' marks.txt
1) Amit     Physics   80
3) Shyam    Biology   87
4) Kedar    English   85

4. 内建数组

语法:

# 创建数组
array_name[index] = value
# 删除数据中的值
delete array_name[index]

如:

shell> awk 'BEGIN {
   fruits["mango"] = "yellow";
   fruits["orange"] = "orange";
   print fruits["orange"] "\n" fruits["mango"];
}'
orange
yellow

遍历数组也很简单,可以使用for循环遍历:

shell> awk 'BEGIN {arr["key1"]="val1"; arr["key2"]="val2"; for(i in arr) {print i, arr[i]}}'
key1 val1
key2 val2

5. 正则表达式

一说到正则表达式可能就会面临正则表达式语法的问题,其实在日常应用中,很少用到高级的正则表达式语法,我们只需要记住一些常用的正则表达式语法就够了:

正面表达式元字符 说明
. 匹配任意单个字符
? 表示?之前的字符出现0次或1次
* 表示*之前的字符出现0次或多次
+ 表示+之前的字符出现1次或多次
^ 匹配行的开始
$ 匹配行的结尾
[] 匹配字符集合,如[0-9]匹配任意数字
[^] 排除字符集合,是[]的逆操作,如[^0-9]表示匹配非数字字符
| 选择,如果`/Call Ball/`,表示匹配Call或Ball
() 分组,如`(Call Ball)`,表示匹配Call或Ball

匹配任意单个字符:

shell> echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f.n/'
fun
fin
fan

匹配开头:

shell> echo -e "This\nThat\nThere\nTheir\nthese" | awk '/^The/'
There
Their

匹配结尾:

shell> echo -e "knife\nknow\nfun\nfin\nfan\nnine" | awk '/n$/'
fun
fin
fan

匹配字符集合:

shell> echo -e "Call\nTall\nBall" | awk '/[CT]all/'
Call
Tall
shell> echo -e "Call\nTall\nBall" | awk '/[^CT]all/'
Ball

选择:

shell> echo -e "Call\nTall\nBall\nSmall\nShall" | awk '/Call|Ball/'
Call
Ball

分组:

shell > echo -e "Apple Juice\nApple Pie\nApple Tart\nApple Cake" | awk '/Apple (Juice|Cake)/'
Apple Juice
Apple Cake

6. 控制语句

AWK的控制语句同C语言语法:

# if condition
if (condition) {
   action
}

# if-else
if (condition) {
   action-1
} else {
   action-2
}

如果是单行,可以省略大括号;

shell> awk 'BEGIN {
    num = 11; 
    if (num % 2 == 0) {
        printf "%d is even number.\n", num; 
    } else {
        printf "%d is odd number.\n", num;
    }
}'
11 is odd number.

7. 循环语句

同C语言语法,支持for循环和while循环:

7.1 for循环

for (initialization; condition; increment/decrement) {
   action
}

如果是单行,可以省略大括号,如下:

shell> awk 'BEGIN { for (i = 1; i <= 3; ++i) print i }'
1
2
3

除此之外for还支持对数组的遍历,语法如下:

for (i in array) {
    action
}
shell> cat for.awk
BEGIN{
    array[0]=0;
    array[1]=1;
    array[2]=2;
    for (i in array) {
        print i;
    }
}
shell> awk -f for.awk
0
1
2

7.2 While循环

语法:

do {
   action
} while (condition)

当只有一行时大括号可以省略,如:

shell> awk 'BEGIN {i = 1; do { print i; ++i } while (i < 4) }'
1
2
3

8. 函数

8.1. 内建函数

AWK支持很多内建函数,这里用的最多的是print和printf,printf跟C语言的printf很类似,当我们要进行一些格式化输出的时候非常有用,如下:

shell> awk 'BEGIN {
   param = 1024.0;
   result = sqrt(param);
   printf "sqrt(%.2f) = %.2f\n", param, result
}'
sqrt(1024.00) = 32.00

更多内建函数见AWK Build-in Functions

8.2 用户自定义函数

除了AWK提供的内建函数外,还支持用户自定义函数,自定义函数也跟C语言类似,只是AWK是弱类型语言,没有类型而且,函数定义语法如下:

function function_name(argument1, argument2, ...) { 
   function body
}

看一个加法的例子:

shell> cat func_demo.awk
function addition(num1, num2) {
   result = num1 + num2
   return result
}

BEGIN {
   res = addition(10, 20)
   print "10 + 20 = " res
}
shell> awk -f func_demo.awk
10 + 20 = 30

9. 输出重定向

9.1 重定向操作符

最后来看一下awk的一个非常重要的特性,支持重定向、追回、管道操作符,有什么用呢,先来看一下简单的例子,将AWK的命令输出重定向到文件中,如下:

shell> awk 'BEGIN { print "Hello, World !!!" > "/tmp/message.txt" }'
shell> cat /tmp/message.txt
Hello, World !!!

这有什么用呢,我们可以利用这个特性来拆分文件,如果将不同级别的日志拆分到不同文件中,如下:

shell> cat log.txt
Debug 1560761852 debug log
Trace 1560761883 trace log
Warning 1560761909 warning log
Fatal 1560761923 fatal log
shell> awk '{print > $1}' log.txt
shell> ls
Debug  Fatal  log.txt  Trace  Warning

9.2 管道

语法:

print items | command

示例:

shell> awk 'BEGIN { print "hello, world !!!" | "tr [a-z] [A-Z]" }'
HELLO, WORLD !!!

9.3 双向通信

AWK可以使用|&和一个外部进程进行通信,并将外部进程执行的结果再发送回AWK,这就是所谓的双端通信,这有什么用呢?用处非常大,说明AWK可以跟外部的任何进程进行进程间通信,而非常方便,这里举个例子:如果我们要计算文件中每一行内容的md5值,该怎么做呢?

我们知道md5sum可以计算文件的md5,但如果要计算文件中的每一行内容的md5,我们可以利用awk把每一行单独提取出来,然后再将每一行的内容通过|&传输给md5sum命令,并将md5sum执行完成的结果再打印出来就OK了,如下:

shell> cat data.txt
first line
second line
third line
shell> md5_line.awk
{
    cmd = "md5sum";
    print $0 |& cmd;
    close(cmd, "to");

    cmd |& getline md5;
    print md5;
    close(cmd);
}
shell> awk -f md5_line.awk data.txt
e1735158246b267bdc0ec11b0b4c1ecc  -
991306dc94d90b914581af4ee2dbd8e6  -
5ffee6590a125f1a159b001625ce599a  -

-- 完 --

参考

[1] https://www.tutorialspoint.com/awk/index.htm
[2] https://coolshell.cn/articles/9070.html
[3] https://blyx.com/public/docs/programacion/Awk_Language_Programming.pdf

相关文章

  • Linux三剑客(grep sed awk) 之 awk

    awk awk****推荐去看朱双印的博客“awk****从放弃到入门”,写的真的很好,本文的awk****就总结...

  • 1. shell入门练习(awk + sed命令)

    1.shell入门练习(awk + sed命令) awk: 批量关闭线程 ps aux |grep nginx |...

  • linux-awk常用命令

    linux-awk常用命令 awk从放弃到入门[https://www.zsythink.net/archives...

  • Linux awk命令详解

    Linux awk命令详解 使用方法 调用awk 入门实例 1. 显示最近登录的5个帐号 awk工作流程是这样的:...

  • shell -- AWK&文本处理 浅析

    markdown 编辑,来写awk真是麻烦awk 入门:awk 是格式化文本处理最常用的工具,日常捞数据、切数据最...

  • Linux三剑客(awk-4)-awk的模式(pattern)

    朱双印——awk从放弃到入门(6):awk模式 我们之前一直在提,awk的使用语法如下: 对于options(选项...

  • awk入门

    AWK 简介 AWK是一种优良的文本处理工具。它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎...

  • AWK 入门

    AWK是一种处理文本文件的语言,也是一个强大的文本分析工具。AWK最早是在1977年在贝尔实验室被发明的,之所以叫...

  • 三十分钟学会AWK

    本文大部分内容翻译自我开始学习AWK时看到的一篇英文文章 AWK Tutorial ,觉得对AWK入门非常有帮助,...

  • Linux三剑客(awk-3)-awk变量

    本文取自朱双印——awk从放弃到入门(3):awk变量 对于awk来说,变量又分为内置变量和自定义变量,输入分隔符...

网友评论

    本文标题:AWK 入门

    本文链接:https://www.haomeiwen.com/subject/rhegfctx.html