内容简介:在开始学Linux的时候就听说过awk这个工具,但当时觉得,这个工具,好像平时用不太到啊,于是就没怎么学。不过最近写脚本的时候,在网上看到了一些awk的脚本,惊叹于awk的文本处理能力,我想,是时候拿起awk这个文本处理神器了。awk其实是先来个简单的程序,在终端输入下面代码:
在开始学 Linux 的时候就听说过awk这个工具,但当时觉得,这个工具,好像平时用不太到啊,于是就没怎么学。不过最近写脚本的时候,在网上看到了一些awk的脚本,惊叹于awk的文本处理能力,我想,是时候拿起awk这个文本处理神器了。
介绍
awk其实是 A ho, W inberger和 K ernighan三位大牛的首字母组合而成的。它既可以指awk这个可执行文件,也可以指awk这种语言,嗯,没错awk是一种语言!
Hello
先来个简单的程序,在终端输入下面代码:
$ awk -F: '$1 == "root" {print $0}' /etc/passwd
解释一下上面的这个命令, -F:
指的是分割符为 :
,后面字符串的意思是,如果被分隔符分隔的第一项为 root
,那就输出这一行到标准输出。而/etc/passwd是awk的处理的文本。
输出结果为:
root:x:0:0:root:/root:/bin/bash
语言
下面讲解一下awk的基本语法,其实awk的语法和C的语法有相似之处,如果不知道怎么用或者忘了,大可以用C的语法试试。
当然,如果忘了awk语法或者某个函数的用法,man吧,特别详细。
模式与行为
从上面这个命令中我们可以窥见awk语法的大致组成,它是有 模式 和 行为 组成的。
对于每一行,如果前面的模式匹配了,那么条件后面紧跟的行为就会被执行。这个模式可以是类似于上面 $1 == "root"
的逻辑表达式,也可以是正则表达式。
上面的一行命令其实可以写成单独的脚本存储为a.awk:
BEGIN { FS=":" #设定分隔符 } $1 == "root" { print $0 }
然后使用命令 awk -f a.awk /etc/passwd
,执行效果是一样的。
模式
awk中的模式有如下几种(man awk):
BEGIN END BEGINFILE ENDFILE /regular expression/ relational expression #也就是$1 == "root"这种,关系表达式 pattern && pattern pattern || pattern pattern ? pattern : pattern #三目!awk强啊 (pattern) ! pattern pattern1, pattern2 #这将会匹配到pattern1到pattern2之间的内容,是一种range pattern,如果忘了,man
正则模式示例,显示当前目录下,大小的单位为K的文件。
$ ls -lh | awk '/([0-9]+\.)?[0-9]+K/ { print $0}'
逻辑表达式示例,显示第3行的内容,NR的含义见下面的
$ echo -e "a \n b \n c" | awk 'NR == 3 {print $0}'
输出为c。
可以用正则来测试变量来匹配吗?
当然可以,见BEGIN&END下面的例子。
BEGIN&END
这两个是特殊的模式,跟在BEGIN后面的行为会在awk处理文件之前执行,一些初始化工作(比如设置FS)可以放到这里。
而END后面的行为则是在文件被处理完毕之后被执行,善后工作可以放到这里。
比如,下面的脚本统计目录下ctime为2019年的文件或目录数量:
#!/usr/bin/awk -f # count2019.awk BEGIN { CNT = 0; # counter } $6~/2019(-[0-9]{2}){2}/ { # 注意这里测试第6个字段是否匹配正则 CNT ++; } END { printf "processing finised, 2019 files/dirs count: %d", CNT }
运行:
$ ls --full-time | awk -f count2019.awk processing finised, 2019 files/dirs count: 4⏎
行为
行为在模式的后面,需要用大括号括住。
行为中的语句可以用 ;
分割,也可以用换行符 \n
分隔。
变量
定义变量
awk中的变量直接用就行,和 python 一样,如果之前没有使用过这个变量,那么它的值为空。
数组
其实awk里面的数组就是python里面的字典,连字符串都能当索引使。
BEGIN { favorites["singer"] = "taylor swift" favorites["song"] = "500 miles" for (key in favorites) { print favorites[key] } }
运行 awk -f array.awk
输出结果如下:
500 miles taylor swift
内置变量
awk中有一些方便的内置变量,如下表(未全部列出):
变量名 | 作用 |
---|---|
FILENAME | 输入的文本文件的文件名,如果是标准输入,空。 |
$0
|
当前记录的内容 |
$1,$2,$3...
|
当前记录被分隔符分割成很多字段 $num
表示num项(1起始) |
FS | 分隔符,默认空格 |
RS |
输入记录分隔符,默认为 \n
|
NF | 当前记录的字段数 |
NR | 已经读入的记录数 |
FNR | 当前输入文件的记录数 |
OFS | 输出字段分隔符,默认空格 |
ORS |
输出记录分隔符,默认换行 \n
|
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
从上面的表中可以看到,其实一个文件是先被RS分隔成记录,然后这个记录再被FS分割成字段,所以准确地说awk其实是以记录为处理单元的,只不过这个RS默认是换行符。
ARGC&ARGV
运行一下下面的程序就知道他们的意思了:
#!/usr/bin/awk -f # argc.awk BEGIN{ print ARGC for (i = 0 ; i < ARGC ; i++) { print ARGV[i] } }
$ awk -f argc.awk /etc/passwd
输出结果:
2 awk /etc/passwd
函数
函数调用的格式可以是 printf("%s %d", "hha", 3)
也可以是 printf "%s %d", "hah", 3
示例:
$ ls -l | awk '{printf "%15s %d\n",$9,$5}' $ ls -l | awk '{printf ("%15s %d\n",$9,$5)}'
内置函数
下面列举一部分常用的内置函数
函数 | 功能 |
---|---|
length(str)
|
字符串长度 |
index(str,sub)
|
sub在str中的索引(1起始),如果无此子串,0 |
match(str, regex)
|
字面意思,0表示不匹配 |
split(str,arr,regex)
|
使用regex分割字符,把子字符串放入arr数组 |
printf(format, expr-list)
|
这个不解释 |
tolower(str)
|
|
toupper(str)
|
|
systime()
|
自1970-01-01,00:00:00至今的秒数,像不像time调用呢? |
strftime([format [,timestamp[,utc-flag]]])
|
返回一个格式化的时间字符串。示例见下面。 |
close(filename)
|
关闭一个文件(awk还能直接输出到文件!) |
delete()
|
删除数组中的一个元素 |
exit(code)
|
退出,code是返回值 |
getline()
|
获取下一行,由于下一行被读了,所以此次记录处理完之后是下下行 |
next()
|
读取下一行,然后继续执行 |
system()
|
就是stdlib中的system那样的功能 |
systime&strftime
$ awk 'BEGIN {print strftime("%F",systime())}'
自定义函数
看个例子就会了:
#!/usr/bin/awk -f # strlen.awk function strlen(str) { return length(str) } BEGIN { message = "hello" printf "length of %s is %d", message, strlen(message) }
控制语句
分支语句
只有一种,那就是 if...else...
,和C中一样的用法。
循环语句
四种,分别是 while
, do...while
, for
和 foreach
(我善做主张起了个名字)
示例如下:
#!/usr/bin/awk -f # loop.awk BEGIN { for (i = 0 ; i < 10 ; i++){ arr[i] = i*2; } for (idx in arr) { printf "arr[%d] = %d\n",idx,arr[idx] } i = 9 while (i >= 0) { arr[i] = 0; i--; } j = 0 do{ print arr[j] j++ } while(j < 10) }
运行 awk -f loop.awk
结果为:
arr[0] = 0 arr[1] = 2 arr[2] = 4 arr[3] = 6 arr[4] = 8 arr[5] = 10 arr[6] = 12 arr[7] = 14 arr[8] = 16 arr[9] = 18 0 0 0 0 0 0 0 0 0 0
输入输出
可以在awk脚本中直接输出到文件中,这需要用到awk中的重定向功能,和 shell 里面的重定向一样,使用的符号是 >,>>
(当然没有输入重定向)
示例:
#!/usr/bin/awk # redirect.awk BEGIN { print "test" > "/tmp/awkoutput" close("/tmp/awkoutput") #一定要close,不然不会输出的,而且不关闭会资源泄漏 }
更多高级用法,就在实践中摸索吧!
参考资料:
《Linux就是这个范儿》(好书)
以上所述就是小编给大家介绍的《Aha awk!》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Algorithms to Live By
Brian Christian、Tom Griffiths / Henry Holt and Co. / 2016-4-19 / USD 30.00
A fascinating exploration of how insights from computer algorithms can be applied to our everyday lives, helping to solve common decision-making problems and illuminate the workings of the human mind ......一起来看看 《Algorithms to Live By》 这本书的介绍吧!