Awk学习笔记
看到前辈的飞快的用awk工具从一堆字符串中切出想要的数据,很是羡慕...
可能是对脚本接触太少,脚本调试又非常困难,以前总不能深入的理解shell的相关命令,今天潜下心来,在学习awk上下来不少功夫,略有收获,记录如下:
1. awk命令格式
man awk出来的英文太恶心,内容也不好练习。网上搜索了不少资料,也不断的实践,总结如下:
awk [命令] ‘[BEGIN {}][pattern{}] [END {}]’file
即awk输入参数可以有三个个:一个是可选的命令,如设置分隔符 –F:;一个是’’中的模式及执行语句块;最后一个是文件名。’’中间至多可以包含三个模式及对应的执行块部分,至少需要一个模式。BEGIN和END是特殊的模式:BEGIN匹配输入前,也就是说跟在它后面的执行语句块在读取文件前执行,整个过程只执行一次;END匹配输入结束,也就是说它后面的执行语句块在所有输入行处理完或者是利用exit提前结束后执行,整个过程只执行一次。Pattern就是指执行其后面语句块的前提条件。当awk读取一行后,就用该行的内容参与Pattern的计算,如果结果是真就执行Pattern后的语句块。Pattern可以是多个pattern利用关系运算符的结果。Pattern可以是正则表达式,也可以是普通的比较。如果pattern被忽略,那么其后面的执行语句块总是被执行。下面举例说明:(test.txt是当前目录下存在的一个文本文件)
awk –F: ‘BEGIN {line=0} {line++;printf(“%s/n”, $1)} END{printf(“line=%d/n”, line)}’test.txt
上面那条命令将输出test.txt的每一行:前面的内容,并最后打印出其总行数。
awk ‘{line++;printf(“%s/n”, $1)} END{printf(“byebye/n”)}’test.txt
上面那条命令将输出test.txt的每一行的第一个空白字符前面的内容,并最后打印出byebye
awk ‘BEGIN {line=0}{if(line++<2){printf{“%s/n”, $0}}} END{printf(“line=%d/n”, line)}’test.txt
上面那条命令将输出test.txt的前两行,并最后打印出其总行数。需要注意的是包含if语句块的{}不能去掉,awk解析器利用它来判断if语句块是读取一行后匹配Pattern后的执行语句块。
2. 在awk中使用shell变量
如果对shell的变量替换可通配符扩展符规则非常了解,其实在awk使用shell变量就很自然就会用了。无奈先前对其通配符扩展规则不求甚解,半瓶子醋让我在这个问题上伤了很大的脑筋。下面对其进行说明,主要是解释:
man awk后,会提到在awk命令中使用shell变量的方法是在需要的地方放置’”$Var”’即可,其中Var是shell变量。举例说明:
#! /bin/sh
Var=”2”
Add=”1+1=”
echo $Add|awk ‘{printf(“%s%d/n”, $0, ‘”$Val”’)}’
上面脚本将打印出1 + 1 = 2
这是为什么呢?其实shell是基于单词的处理,单词之间空白符分割,如果其中有通配符,便对齐进行扩展。在双引号””中的将进行变量替换及通配符操作,其中内容整体作为一个单词;在单引号’’中将不进行任何扩展;单引号和双引号都是使用最先匹配原则,即不具有贪婪性如果引号之间无空白字符,则它们进行连接成为一个单词;连接完成后,作为单词边界的单引号和双引号将被去除,但是不是作为边界的引号将保留(如’’中的双引号)。回到上面的示例,仔细分析’”$Val”’的第一个单引号与整个语句的最前面的单引号匹配,而’”$Val”’后面的单引号与整个语句的最后一个’相匹配。”$Val”经过变量替换后就是”Hello”了。然后整体连接后, ‘{printf(“%s is , %s/n”, $1, ‘”$Val”’)}’就相当于{printf(“%s is , %s/n”, $1,”Hello”)}被传递作为awk的第一个参数。很明显”$Val”中的双引号不能去除,因为去除后,Hello相当于一个awk变量,没有定义的awk变量是为null的。
再细心一点,我们把上面的脚本换成如下的脚本:
#! /bin/sh
Var=”2”
Add=”1+1=”
echo $Val|awk ‘{printf(“%s%s/n”, ‘”$Add”’, $0)}’
我们期待输出Hello, Ladies and gentle man。然而,很抱歉,我们得到如下的错误:
awk: {printf("%s%s/n", 1 + 1 = , $0)}
awk: ^ syntax error
其实错误很明显了,1 + 1 = 被要求成一个字符串被打印,当然是错误的了,解决的方式很明显是将‘”$Add”’写成”‘”$Add”’”,相当于给传递给awk的命令中的1 + 1 =加了个双引号。
3. 将awk结果输出是很简单的shell知识
4. 提前终止awk的方法是调用exit,close文件并不导致执行结束。