awk学习之cookbook技巧.md
#Awk One-Liners Explained, Part 1: File Spacing, Numbering and Calculations
##1.Line Spacing
1.每行后面都加上一个空行
awk '1; { print "" }' #awk学习之cookbook技巧
awk 程序包含一系列的 parttern-action(模式-动作)的语句。类似这样‘pattern{action}’的结构。
这个例子中包含了2个语句,一个是 “1”,另一个是“{print “” }”,模式和动作都可以省略的其中一个的。
如果模式省略了,默认是对所有的输入内容按行来出来的。如果是动作省略的默认是“{print }”。
注意awk程序是面向行的。awk学习之cookbook技巧
上面的等同于下面这个程序
awk '1 { print } { print "" }' #awk学习之cookbook技巧
动作只有在模式匹配的情况下才执行。这里例子中的模式是“1”,这个模式总是true,也就是每一行都会匹配,
每一行也都会执行动作的。所以也等价于下面的代码:
awk '{ print } { print "" }' #awk学习之cookbook技巧
awk的print语句总是会在最后打印一个ORS(output record separator)变量的,这个值模式是换行,
也就是\n #awk学习之cookbook技巧
这里例子中的第一个print语句后面没有接任何参数,所有默认等于print $0
,也就是打印整行内容,
$0代表的是整行内容。 #awk学习之cookbook技巧
例子中的第二个print 打印一个空字符串,也是上面都不输出,打上print会在最后加上一个换行,所以呢
这里就打印出来了一个空行了。#awk学习之cookbook技巧
2.另外一个给每行后面加上空行的技巧
awk 'BEGIN { ORS="\n\n" }; 1' #awk学习之cookbook技巧
BEGIN是一个特殊的模式,表示在读取内容之前无条件执行后面的动作。
这个技巧中是在动作语句中对ORS变量重新赋值了,将一个换行变成两个换行了。
后面 的1 等价于 {print} ,这样就达到了每行后面都加上新的空行的目的。
$ awk 'BEGIN { ORS="\n\n" }; 1' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
3.在每个非空的行后面添加空行
awk 'NF { print $0 "\n" }' #awk学习之cookbook技巧
这个技巧用到了awk中的另外一个特殊变量NF(number of fields)。这个表示每行被awk分割为多少个字段,
也就是多少列,默认是安装空格分割的。例如“this is a test”这行会被分割为4个字段。
如果是空行,是不会分割的,也就是NF的值是0。#awk学习之cookbook技巧
这里使用NF作为模式,只有NF值大于0条件才是真,后面的动作才执行。
后面的动作是print $0,也就是打印整行内容,print第二个参数是个换行,也就是后面加个新的空行。
4、在每行后添加两个空行
awk '1; { print "\n" }' #awk学习之cookbook技巧
1是等于{print}的,所以上面的可以等价于下面这个 #awk学习之cookbook技巧
awk '{ print; print "\n" }' #awk学习之cookbook技巧
首先是打印一整行内容,然后再打印一个换行。 #awk学习之cookbook技巧
##2.Numbering and Calculations
5、为每个文件的内容添加行号
awk '{ print FNR "\t" $0 }' #awk学习之cookbook技巧
这则技巧是在没一行的开头加上FNR(file line number行号)然后是一个\t( tab键),最后是整行内容。
FNR变量记录了当前的行号。FNR会每次重置为0的。
$ awk '{ print FNR "\t" $0 }' ffmpeg.sh
1 #!/bin/bash #awk学习之cookbook技巧
2
3 INPUT_FILE="$1"
4 ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
$
6、为所有文件的所有行统一添加行号
awk '{ print NR "\t" $0 }' #awk学习之cookbook技巧
这个和上面的那个例子类似,只是这里使用NR(line number)变量了,这个不会重置为0的。
$ awk '{ print FNR "\t" $0 }' ffmpeg.sh ffmpeg.sh
1 #!/bin/bash #awk学习之cookbook技巧
2
3 INPUT_FILE="$1"
4 ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
1 #!/bin/bash #awk学习之cookbook技巧
2
3 INPUT_FILE="$1"
4 ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
$ awk '{ print NR "\t" $0 }' ffmpeg.sh ffmpeg.sh
1 #!/bin/bash #awk学习之cookbook技巧
2
3 INPUT_FILE="$1"
4 ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
5 #!/bin/bash #awk学习之cookbook技巧
6
7 INPUT_FILE="$1"
8 ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
$
我们可以看到当作用到2个文件来显示行号的时候 FNR是会在第二个文件重置为0 的。
NR变量则不会重置为0 的。
7、 格式化行号
awk '{ printf("%5d : %s\n", NR, $0) }' #awk学习之cookbook技巧
这个例子使用到了printf 函数,这个类似bash/c语言中的printf()函数。这个函数是不会在每行结尾追加打印ORS,也就是不会打印换行的。
$ awk '{ printf("%5d : %s\n", NR, $0) }' ffmpeg.sh ffmpeg.sh #awk学习之cookbook技巧
1 : #!/bin/bash #awk学习之cookbook技巧
2 :
3 : INPUT_FILE="$1"
4 : ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
5 : #!/bin/bash #awk学习之cookbook技巧
6 :
7 : INPUT_FILE="$1"
8 : ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
8.非空行前面添加行号
awk 'NF { $0=++a " :" $0 }; { print }' #awk学习之cookbook技巧
awk中是可以使用变量的,当然也可以使用自定义的变量,和bash是类似的,不需要先定义在使用,可以直接使用的。
之前我们用到的那些个变量都是awk自己定义的。#awk学习之cookbook技巧
这个例子怎么理解呢?
首先 这里是2个模式动作语句。第一个是 NF { $0=++a " :" $0 }
,第二个是{ print }
第一个里面 ++a是定义了一个变量a,这里初始就是0(数字零),而不是什么空或者空字符串。
为啥是数字也是因为这个++操作符是作用到数字上面的。#awk学习之cookbook技巧
然后执行++操作(类似c语言里面的前置++)a第一次执行就会变为1了。
什么时候第一次执行呢也就是第一个不是空行的时候才是首次执行。因为NF模式匹配非空行。上面有个例子讲过。
然后是++a “ :” $0
这3个值按照字符串拼接那样拼接起来,然后一起重新复制给变量$0了,$0表示整行内容,
这里就实现了给非空行重新设置行号的目的了。注意拼接字符串不能使用加号,加号只能作用到数字上面。
第一个模式动作语句是不打印内容的。#awk学习之cookbook技巧
然后是第二个模式动作语句,里面只有一个print,默认就是打印$0,默认就是打印整行内容。
这里不管是空行,还是非空行都统统的打印出来,非空行因为是之前在第一个模式动作中重新被
赋值了,这里也就实现了打印非空行行号的目的了。#awk学习之cookbook技巧
同时我们可以看到这个awk程序作用到2个文件的时候,变量a是不会被重置的。#awk学习之cookbook技巧
$ awk 'NF { $0=++a " :" $0 }; { print }' ffmpeg.sh ffmpeg.sh #awk学习之cookbook技巧
1 :#!/bin/bash #awk学习之cookbook技巧
2 :INPUT_FILE="$1"
3 :ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
4 :#!/bin/bash #awk学习之cookbook技巧
5 :INPUT_FILE="$1"
6 :ffmpeg -y -i "$INPUT_FILE" -vf drawtext="fontfile=fonts/simsun.ttc: text='欢迎光临 马哥的淘宝店<马哥私房菜> 地址是:shop592330910.taobao.com':fontcolor=red:fontsize=40:box=1:boxcolor=black@0:x=if(eq(mod(t\,3)\,0)\,rand(0\,(w-text_w))\,x):y=h-text_h" -codec:a copy "new.${INPUT_FILE}"
9.计算文件行数(模拟 wc -l 命令)
awk 'END { print NR }' #awk学习之cookbook技巧
这里又用到了一个特殊的模式END,这个表示所有行处理完,最后在执行这个模式后面的动作。
这个例子就是打印NR的值,也就是最终的行数。 #awk学习之cookbook技巧
$