awk是对文本,按行进行处理。它可以将文本,按行以某一字符进行分割,分成不同的段,其中$0代表整个文本行,$n代表第n段,而默认的分隔符是”空格键”或”Tab键”。
Awk运作的模式如下:
简易例子如下:
如果要取出账号与登陆者的ip,且账号与ip之间用tab键隔开,则命令如下:
注意:
1、”\t”必须得用双引号引住,否则是识别不了的。
2、发现第2行和第4行有点乱,那是因为在原始的last中,第一段和第三段就是那样的,所以,用awk时,一定要确认好数据的格式。
3、发现上面命令中,并没有”条件类型”的限制,那是因为我们要处理文本的每一行。
awk的处理流程:
从上述流程知,awk是以行为一次处理的单位,而以字段为最小的处理单位,那么awk如何知道所处理的数据有几行、几栏呢,这就需要awk的内建变量帮忙啦
简易例子:
显然,输出是账户名、awk当前处理的哪一行、awk当前处理行的字段数。
注意:awk所有的动作都是用单引号引住的,所以用print打印时,非变量的文字部分,一定要用双引号引住,包括用printf。
4.9.1 awk的逻辑运算符
既然命令中可以写”条件类型”,那自然需要一些逻辑运算啦,如下:
值得注意的是表格中没有=运算符,它和程序语言中一样,如果是直接给变量赋值,就是直接用的=,而不是’==’。
简易例子:
这个只是让你知道,passwd中的内容格式是什么,和下面的cat /etc/passwd 是不对应的。
显然,将文本行的分隔符改为了”:”,而且对于每一行,只有第三段的值<10,才输出第一个字段和第三个字段。但是奇怪的是,为什么第一行没有按指定的要求输出呢?
那是因为,在我们读入第一行时,那些变量$1,$2…… 还是以预设的空格为分隔,所以我们虽然定义了 FS=”:”,则仅能在第二行处理时才能生效,那么如何解决这个问题呢?
可以预先设定awk的变量,利用BEGIN这个关键词
注意:这个BEGIN 并不等价于”NR==1”,它表示在”NR==1”之前就进行处理了,相应的还有一个END呢。
4.9.2 awk实现计算功能
简易例子:
薪资数据表pay.txt如下:
Name 1st 2nd 3th
songbw 100 200 300
xiaosh 2 3 45
majf 7 8 9
用awk 命令实现薪资统计
(base) localhost:~ songbw$ cat pay.txt |\
> awk 'NR==1 {printf "%10s %10s %10s %10s %10s\n", $1, $2, $3, $4, "Total"}
> NR >= 2 {total = $2 + $3 + $4; printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total }'
Name 1st 2nd 3th Total
songbw 100 200 300 600.00
xiaosh 2 3 45 50.00
majf 7 8 9 24.00
显然,上述是算每个人三个月工资的总和。
注意:
1、
2、格式化输出时,在printf的格式设定当中,务必加上’\n’,才能进行分行,而print 是不需要的!
3、与bash shell的变量不同,在awk当中,变量可以直接使用,不需要加$!
awk的动作{}也支持if(条件)哦,上述子,可以更改如下:
另外awk可以帮我们进行循环计算,这是属于高级课程,以后有需要再学吧。
简单小例子:
awk -F: '{if($1>10) {print $1}}' /etc/passwd
以后稍微参考下,就可以写简单的if语句
参考地址:
http://phi.sinica.edu.tw/aspac/reports/94/94011/
http://linux.vbird.org/linux_basic/0330regularex/awk.pdf
4.9.3 awk打印引号
1、打印双引号
首先,awk 打印的字符串是要加引号的,如
awk '{print "songbw"}' generatorRecordings.sh
打印songbw这个字符串是要加引号的,那么正常逻辑打印双引号应该为 awk '{print """}' generatorRecordings.sh
但是出现错误:
提示没有终止的字符串,提示很正确,因为三个双引号,两个双引号之间是一个string,但是现在只有三个,也就是说有一个字符串没有写完,解决办法,打印出来的引号需要用\转义,如下:
awk '{print "\""}' generatorRecordings.sh
2、打印单引号
awk '{print "'\''"}' # 放大: awk '{print " ' \ ' ' " }'
使用一个双引号“”,然后在双引号里面加入两个单引号‘’,接着在两个单引号里面加入一个转义的单引号\',输出单引号。
例子:
awk '{print "'\''"}' generatorRecordings.sh
参考书籍:
鸟哥的linux私房菜
文本test.txt中内容:
# flume.conf: A single-node Flume configuration
# Name the components on this agent
a3.sources = r1 a3.channels = c1
a3.sinks = k1
a3.channels = c1
脚本try.sh中内容:
#!/bin/bash
i=4
sed 's/a3/a'$i'/' test.txt
执行脚本try.sh后的结果:
发现,每一行的第一个匹配的都进行了改变
而打开test.txt后的内容和原来相比,并没有发生变化
如果想让test.txt文本中发生改变,需要加上-i 命令参数,如下,将
sed 's/a3/a'$i'/' test.txt
改为
sed -i 's/a3/a'$i'/' test.txt
如果想让test.txt文本中所有匹配的都进行改变,需要加上/g,具体如下:
sed -i 's/a3/a'$i'/g' test.txt
sed具体用法如下:
sed 's/原字符串/替换字符串/'
单引号里面,s表示替换,三根斜线中间是替换的样式,特殊字符需要使用反斜线”\”进行转义,但是单引号”‘”是没有办法用反斜线”\”转义的,这时候只要把命令中的单引号改为双引号就行了,例如:
代码如下:
sed "s/原字符串包含'/替换字符串包含'/" //要处理的字符包含单引号
命令中的三根斜线分隔符可以换成别的符号,这在要替换的内容有较多斜线是较为方便,只需要紧跟s定义即可,例如换成问号”?”:
代码如下:
sed 's?原字符串?替换字符串?' //自定义分隔符为问号
可以在末尾加g替换每一个匹配的关键字,否则只替换每行的第一个,例如:
代码如下:
sed 's/原字符串/替换字符串/g' //替换所有匹配关键字
配指定行的例子:
sed '2s/原字符串/替换字符串/g' //替换第2行
sed '$s/原字符串/替换字符串/g' //替换最后一行
sed '2,5s/原字符串/替换字符串/g' //替换2到5行
sed '2,$s/原字符串/替换字符串/g' //替换2到最后一行