awk(三位作者的名字命名):文本分析工具,Linux及unix环境中功能强大的数据处理工具之一。
相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。
简单来说awk就是把文件逐行的读入,默认以空格为分隔符将每行切片,切开的部分再进行各种分析处理。
awk的特点:使用直译器(Interpreter)不需先行编译; 变量无类型之分(Typeless), 可使用文字当数组的下标(Associative Array)...等特色. 因此, 使用awk撰写程序比起使用其它语言更简洁便利且节省时间. awk还具有一些内建功能, 使得awk擅于处理数据行(Record), 字段(Field)型态的资料; 此外, awk内建有pipe的功能, 可将处理中的数据传送给外部的 Shell命令加以处理, 再将Shell命令处理后的数据传回awk程序, 这个特点也使得awk程序很容易使用系统资源.
命令语法格式:
awk '{pattern + action}' 或者 awk 'pattern {action}'
awk程序的主要结构:
awk程序中主要语法是 Pattern { Actions}, 故常见之awk 程序其型态如下 :
Pattern1 { Actions1 }
Pattern2 { Actions2 }
......
PatterN{ ActionsN }
pattern:可接受不同形态的Pattern.一般使用关系表达式来当成pattern.
如:>,<,>=,<-,==,!= 等关系运算符。
此外,awk还提供~(match)及!~(not match)两个关系运算符:如 A ~ B 表示字符串A中是否包含B表达式的子字符串。english ~ /en/
actions:
Actions 是由许多awk指令构成. 而awk的指令与 C 语言中的指令十分类似.
awk的 I/O指令 : print, printf( ), getline...
awk的 流程控制指令 : if(...){..} else{..}, while(...){...},for(..,..,..){...},do{...}while(..)
例如:awk 'BEGIN{a="helloword";if(a~/hello/){print "ok"}}'
![e81b93ef706937557b063a0b925627b4.png](https://i-blog.csdnimg.cn/blog_migrate/5b96b285a106d763ec8fd6cfc95006b4.png)
echo | awk 'BEGIN{a="helloworld"}a~/hello/{print "0k"}';//此语法分成两个pattern+action模式;1.BEGIN{a="2222helloworld"};2.a~/222/{print "ok"}; 使用echo 的原因 awk往往后面匹配相关的文件,按行号进行读取,取消echo | 第二个匹配模式不会执行,会等待输入行信息,echo | 会把空内容重定向到awk中(即模拟文件读取)直接运行第二个pattern+action
awk的字段含义:
$0: 内容为awk读入的数据行的数据
$1: 每行切片的第一个字段的数据
$2: 每行切片的第二个字段的数据
...以此类推
awk工作流程:
当awk从数据文件中读取一个数据行时, awk会使用内建变量$0予以记录.每当$0被改动时(例如 : 读入新的数据行 或 自行变更 $0,...)awk 会立刻重新分析$0的字段情况, 并将$0上各字段的数据用$1, $2, ..予以记录.若数据文件中还有未读取的数据,则继续执行下一行。
awk内置变量:
ARGC:命令行参数个数
![af759c3dfd015f157627f8c087505d9c.png](https://i-blog.csdnimg.cn/blog_migrate/4abe95193de6a338697fb4e5e34f6e0e.png)
ARGV:命令行参数排列(基于索引下标获取ARGC参数的值)
![39e4b96244f6aaf136c9234f648d3a75.png](https://i-blog.csdnimg.cn/blog_migrate/034d1322d7efe48dd61b46d831299e04.png)
ENVIRON:支持队列中系统环境变量的使用
![be334eb9fbb71c0a28a5085fc2318e94.png](https://i-blog.csdnimg.cn/blog_migrate/d4d4602db424509ef3face3baf9d8286.jpeg)
FILENAME:awk浏览的文件名
![3d220d39a65b8930ea3b0a0fb90d6e0a.png](https://i-blog.csdnimg.cn/blog_migrate/eba62961ccbbd128a5b627c63239ea06.png)
FNR:浏览文件的记录数
![7f4006b31b55176e26baa673083039a0.png](https://i-blog.csdnimg.cn/blog_migrate/554bd2049b0e9c2aa580ec85003e61a4.jpeg)
FS(fields separator):设置输入域分割符,等价于命令行-F选项
![c5e7d4ae151d568bb43f1760f574286a.png](https://i-blog.csdnimg.cn/blog_migrate/02bc54f94f46203919d0e557a1574c24.png)
NF(number of fields):浏览记录的域的个数
![e45cfee4ecbee5c4a49b673e0713271c.png](https://i-blog.csdnimg.cn/blog_migrate/3e3d647c4a3bc7ff7bef0336719290a4.jpeg)
NR(number of rows) :已读的记录数
![a2663130d7dc002a402a83d112d4aaa7.png](https://i-blog.csdnimg.cn/blog_migrate/b55ff557d15314716c475e1125eb8028.png)
OFS:输出域分割符
![91dcadd1f5f4766962cb34eac93301ab.png](https://i-blog.csdnimg.cn/blog_migrate/9476215f4fe33a88c6e028dd279983ee.png)
ORF:输出记录分割符
![f91c82f04df6afb550fc4a03c39b2c59.png](https://i-blog.csdnimg.cn/blog_migrate/2ae459c0de88dcafd06dfa6dcecb8b78.png)
RS:控制记录分割符
![0115628413fad14a6215afb0b1f0f762.png](https://i-blog.csdnimg.cn/blog_migrate/464c2496fb9027992ec52a1d6c1b2f36.png)
注:所谓的域即表示字段,所谓的记录即表示行
awk中的数组:
awk程序中允许使用字符串当做数组的下标(index).
使用字符串当数组的下标(index).
使用数组前不必声明数组名及其大小.
![81b24d73b5779a47a1fea84faf30c665.png](https://i-blog.csdnimg.cn/blog_migrate/2a6013a6d3bb6a4e3a664259843ccc39.png)
awk语法:
1.命令行模式:
awk 'BEGIN{a="helloword";if(a~/hello/){print "ok"}}'
echo | awk 'BEGIN{a="helloworld"}a~/hello/{print "0k"}';
2.文本模式:
awk -f awk程序文件名 数据文件名
如:
![251f47593d6c67ee5a0df392f4dae36b.png](https://i-blog.csdnimg.cn/blog_migrate/412bfe5eec5341b481f1cc348cfb36f0.png)
![7af62a7afe4250ed250f7e43ce473ebd.png](https://i-blog.csdnimg.cn/blog_migrate/9da6876ead97d78ead8608b1f182f8e2.png)
awk -f awk主程序文件名 -f awk函数文件名 数据文件文件名
![70d8c74fd3fc5cc2672ea2c748be4b2e.png](https://i-blog.csdnimg.cn/blog_migrate/b48d50a1cdcdc844528bcf1f32bafa76.png)
![9a4b13c816675e13af284bb96efc81e5.png](https://i-blog.csdnimg.cn/blog_migrate/e8298fc61b5a9587e12fdc55cdd16eec.jpeg)
![30bd7d2cbc304a80ad40edc0cf13f047.png](https://i-blog.csdnimg.cn/blog_migrate/893e914342bbaf6d75e6242aafe4536a.jpeg)
awk的使用:
1.awk 程序中使用Shell命令:
awk程序中允许呼叫Shell指令. 并提供管道解决awk与系统间数据传递的问题. 所以awk很容易使用系统资源.
如:打印在线人数。
![3e82670fc99ec478456109ec14f94354.png](https://i-blog.csdnimg.cn/blog_migrate/e2e787b7a4342f99e65889b20fa55703.jpeg)
![91a2f0259d9b70e7088ed3948a097941.png](https://i-blog.csdnimg.cn/blog_migrate/83714b45775bfcff694329832be562cb.png)
awk 'BEGIN{while("who"|getline){n++} print n}'打印在线人数。"|" 为 awk 中表示管道的符号. awk 把 | 之前的字符串"who"当成Shell上的命令, 并将该命令送往Shell执行, 执行的结果(原先应于屏幕印出者)则藉由pipe送进awk程序中.
getline var < file所指定的 file变量 var(var省略时,表示置于$0)
getline varpipe 变量变量 var(var省略时,表示置于$0)
getline var见 注一变量 var(var省略时,表示置于$0)
2.重定向输出到文件:
awk中任何输出函数之后皆可借助使用与UNIX 中类似的 I/O 重定向符, 将输出的数据重定向到指定的文件; 其符号仍为 > (输出到一个新产生的文件) 或 >> ( 添加输出的数据到文件末尾 ).
![9eb2a93a13b2438788a993af863e6ff1.png](https://i-blog.csdnimg.cn/blog_migrate/33a8a6d1f168a7a6a240881fd258ed41.png)
![8bff34043c90d3074837f31f9a074e26.png](https://i-blog.csdnimg.cn/blog_migrate/34a067c377183fca03bcc4f3f79161df.png)
注:awk程序中, 文件名称 hello.txt 的前后须以" (双引号)括住, 表示 hello.txt 为一字符串常量. 若未以"括住, 则hello.txt将被awk解释为一个变量名称.在awk中任何变量使用之前, 不必事先声明. 其初始值为空字符串(Null string) 或 0.因此程序中若未以 " 将 hello.txt 括住, 则 hello.txt 将是一变量, 其值将是空字符串, 这会在执行时造成错误(Unix 无法帮您开启一个以空字符串为文件名的文件).
3.awk中如何利用系统资源:
awk程序中很容易使用系统资源. 这包括在程序中途调用 Shell 命令来处理程序中的部分数据; 或在调用 Shell 命令后将其产生的结果交回 awk 程序(不需将结果暂存于某个文件). 这一过程是借助 awk 所提供的管道 (虽然有些类似 Unix 中的管道, 但特性有些不同),及一个从 awk 中呼叫 Unix 的 Shell 命令的语法来达成的.
awk 提供与 UNIX 用法近似的 pipe, 其记号亦为 "|". 其用法及含意如下 :
awk程序中可接受下列两种语法:
[a. 语法] awk output 指令 | "Shell 接受的命令"
![3528e62826ce1ce28a27e400d6cb9ec6.png](https://i-blog.csdnimg.cn/blog_migrate/40fb4a45ffa96395f6b0f7f668b7c963.png)
[b. 语法] "Shell 接受的命令" | awk input 指令
( 如 : "ls " | getline)
![7d5047bd0df129d333ef07215f6be640.png](https://i-blog.csdnimg.cn/blog_migrate/ac6a32c49a5c63539ffab43069a182dd.jpeg)
注 : awk input 指令只有 getline 一个.
awk output 指令有 print, printf() 二个.
在a 语法中, awk所输出的数据将转送往 Shell , 由 Shell 的命令进行处理.以上例而言, print 所输出的数据将经由 Shell 命令 "sort -k 1" 排序后再送往屏幕(stdout).
上列awk程序中, "print$1, $2" 可能反复执行很多次, 其输出的结果将先暂存于 pipe 中,等到该程序结束时, 才会一并进行 "sort -k 1".
须注意二点 : 不论 print $1, $2 被执行几次, "sort -k 1" 的执行时间是 "awk程序结束时",
"sort -k 1" 的执行次数是 "一次".
在 b 语法中, awk将先调用 Shell 命令. 其执行结果将通过 pipe 送入awk程序,以上例而言, awk先让 Shell 执行 "ls",Shell 执行后将结果存于 pipe, awk指令 getline再从 pipe 中读取数据.
使用本语法时应留心: 以上例而言,awk "立刻"调用 Shell 来执行 "ls", 执行次数是一次.
getline 则可能执行多次(若pipe中存在多行数据).
除上列 a, b 两种语法外, awk程序中其它地方如出现像 "date", "cls", "ls"... 这样的字符串, awk只把它当成一般字符串处理.
awk程序由三个主要部分构成 :
[ i.] Pattern { Action} 指令
[ ii.] 函数主体. 例如 : function double( x ){ return 2*x }
[ iii.] Comment ( 以 # 开头识别之)
awk 的输入指令 getline, 每次读取一列数据. 若getline之后
未接任何变量, 则所读入之资料将以$0 记录, 否则以所指定的变量储存之.
4. awk提供另一个调用Shell命令的方法, 即使用awk函数system("shell命令")
![de0bc9280a4ac35fa4178cb889a9a5a0.png](https://i-blog.csdnimg.cn/blog_migrate/fd0f88ae2f0fa05977849cbcd2db34f2.png)
但使用 system( "shell 命令" ) 时, awk无法直接将执行中的部分数据输出给Shell 命令. 且 Shell 命令执行的结果也无法直接输入到awk中.
5.执行awk程序的几种方式
本小节中描述如何将awk程序直接写在 shell script 之中. 此后使用者执行 awk 程序时, 就不需要每次都键入 " awk -f awk程序文件 数据文件" .
script 中还可包含其它 Shell 命令, 如此更可增加执行过程的自动化.
建立一个简单的 awk程序 hello.awk, 如下:
![608e458db096e3565ecdc4ffc9b72538.png](https://i-blog.csdnimg.cn/blog_migrate/dd81f18869ed1485ab8b83a38ca20cf1.png)
![50538cd86e805f2009ac23837ba07210.png](https://i-blog.csdnimg.cn/blog_migrate/70be1e0826e9338af8cdd513f582001d.jpeg)
这个程序执行时会把数据文件的内容 print 到屏幕上( 与cat功用类似 ).
print 之后未接任何参数时, 表示 "print $0".
若欲执行该awk程序, 来印出文件 staff.txt及 ret.txt 的内容时,
必须于 UNIX 的命令行上执行下列命令 :
方式一 awk -f mydump.awk statt.txt ret.txt
方式二 awk '{print}' statt.txt ret.txt第二种方式系将awk 程序直接写在 Shell 的命令行上, 这种方式仅适合较短的awk程序.
方式三 建立如下之 shell script, 并取名为 awk.sh,
#!/bin/sh
# 注意以下的 awk 与 ' 之间须有空白隔开
awk '
{print}
' $*
# 注意以上的 ' 与 $* 之间须有空白隔开
执行 awk.sh 之前, 须先将它改成可执行的文件(此步骤往后不再赘述). 请执行如下命令:
$ chmod +x awk.sh
往后使用者就可直接把 awk.sh 当成指令, 来display任何文件.
例如 :
![6d4c7748ee2e9bf64fbae323d928a490.png](https://i-blog.csdnimg.cn/blog_migrate/d6f67646029aef14a904a22938026286.jpeg)
[ 说 明 : ]
在script文件 awk.sh 中, 指令"awk"与第一个 ' 之间须有空格(Shell中并无" awk' "指令).
第一个 ' 用以通知 Shell 其后为awk程序.
第二个 ' 则表示 awk 程序结束.
故awk程序中一律以"括住字符串或字符, 而不使用 ' , 以免Shell混淆.
$* 为 shell script中的用法, 它可用来代表命令行上 "awk.sh之后的所有参数".
例如执行 :
$ ./asw.sh staff.txt ret.txt
事实上 Shell 已先把该指令转换成 :
awk '
{ print}
' staff.txt ret.txt
本例中, $* 用以代表 "staff.txt ret.txt". 在Shell的语法中, 可用 $1 代表第一个参数, $2 代表第二个参数. 当不确定命令行上的参数个数时, 可使用 $* 表之.
awk命令行上可同时指定多个数据文件.
以awk -f hello.awk staff.txt ret.txt为例,awk会先处理staff.txt, 再处理 ret.txt. 此时若文件无法打开, 将造成错误.
例如: 不存在文件"file_no_exist", 则执行
$ awk -f hello.awk file_no_exit
将产生运行时错误(无法打开文件).
但某些awk程序 "仅" 包含以 BEGIN 为Pattern的指令. 执行这种awk程序时, awk并不须开启任何数据文件.此时命令行上若指定一个不存在的数据文件,并不会产生 "无法打开文件"的错误.(事实上awk并未打开该文件)
例如执行:
$ awk 'BEGIN {print "Hello,World!!"} ' file_no_exist
该程序中仅包含以 BEGIN 为 Pattern 的 Pattern {actions}, awk 执行时并不会开启任何数据文件; 所以不会因不存在文件file_no_exit而产生 " 无法打开文件"的错误.
awk会将 Shell 命令行上awk程序(或 -f 程序文件名)之后的所有字符串, 视为将输入awk进行处理的数据文件文件名.
若执行awk的命令行上 "未指定任何数据文件文件名", 则将stdin视为输入之数据来源, 直到输入end of file( Ctrl-D )为止.
读者可以用下列程序自行测试, 执行如下命令 :
$ awk -f hello.awk #(未接任何数据文件文件名)
或
$ ./awk.sh #(未接任何数据文件文件名)
将会发现: 此后键入的任何数据将逐行复印一份于屏幕上. 这情况不是机器当机 ! 是因为awk程序正处于执行中. 它正按程序指示, 将读取数据并重新dump一次; 只因执行时未指定数据文件文件名, 故awk 便以stdin(键盘上的输入)为数据来源. 读者可利用这个特点, 设计可与awk即时聊天的程序.
6.自定义函数的使用
awk不仅能自动分割字段, 也允许使用者改变其字段切割方式以适应各种格式之需要. 使用者也可自定义函数, 若有需要可将该函数单独写成一个文件,以供其它awk程序调用.
![3721521938e2656604555c4c124b7a1a.png](https://i-blog.csdnimg.cn/blog_migrate/6c0858b6e32045eb688d4a1eddb816e9.jpeg)
7.使用getline来读取数据
![c4ca350d4edd1be0d3230fd00d790011.png](https://i-blog.csdnimg.cn/blog_migrate/ba3b7f937a04c754f9aecd26512de858.png)
![8e1a43edfd0545c3b2121dde46b8b851.png](https://i-blog.csdnimg.cn/blog_migrate/df730b7f49c29d9e81e6d2e5b4229e35.png)
8. 如何读取命令行上的参数
大部分的应用程序都允许使用者在命令之后增加一些选择性的参数,执行awk时这些参数大部分用于指定数据文件文件名,有时希望在程序中能从命令行上得到一些其它用途的数据. 本小节中将叙述如何在awk程序中取用这些参数.
![e00e8f19b1ec608183271c0f747e04ee.png](https://i-blog.csdnimg.cn/blog_migrate/631eae5d89b5c3c005598650ca63acc9.png)
ARGC : 为一整数. 代表命令行上, 除了选项-v, -f 及其对应的参数之外所有参数的数目.
ARGV[ ] : 为一字符串数组. ARGV[0],ARGV[1],...ARGV[ARGC-1].
分别代表命令行上相对应的参数.