AWK 是什么?
AWK 是一种用于处理文本的工具。AWK工具也有自己的语言,它在很多方面和shell非常类似,在AWK创造之初,其目的主要都是用于文本处理,所以这种语言的基本语法都是只要在输入数据能够匹配,就执行指定的命令。AWK扫描传入目标文件每一行,查找与命令行中所给出的匹配模式。如果发现匹配就执行指定动作。如果找不到匹配内容就继续处理下一行。
虽然好多操作都很复杂,不过命令语法始终是下面这样的格式:
awk ‘{pattern + action}’ {filenames}
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号 ({}) 不需要在程序中始终出现,它们主要是用于根据特定的模式对一系列指令进行分组。
下面给出一些awk的用法技巧
1. awk ‘{code}1’ 中的“1”是干什么的?
一个完整的awk语句为:Awk ‘[patten]{action}……’, 其中pattern缺省为1,action缺省为{print}。
那么awk ‘1’完整的写法就是awk ‘1{print}’; 同理,awk ‘{print}’完整的写法也是awk ‘1{print}’。
2. NR和FNR的区别是啥?
NR: 当前行记录数。
FNR: 当前文件的行记录数。
当awk处理的文件数超过1时,NR和FNR才会有区别。例如:
cat file
a
b
c
d
e
f
awk ‘{print “NR = ” NR ” FNR = ” FNR, $0}’ file
NR = 1 FNR = 1 a
NR = 2 FNR = 2 b
NR = 3 FNR = 3 c
NR = 4 FNR = 4 d
NR = 5 FNR = 5 e
NR = 6 FNR = 6 f
awk ‘{print “NR = ” NR ” FNR = ” FNR, $0}’ file file
NR = 1 FNR = 1 a
NR = 2 FNR = 2 b
NR = 3 FNR = 3 c
NR = 4 FNR = 4 d
NR = 5 FNR = 5 e
NR = 6 FNR = 6 f
NR = 7 FNR = 1 a
NR = 8 FNR = 2 b
NR = 9 FNR = 3 c
NR = 10 FNR = 4 d
NR = 11 FNR = 5 e
NR = 12 FNR = 6 f
3. Awk怎么引入变量?
有两种方法:
: awk -v var=$VAR ‘{code}’
: awk ‘{CODE}’$VAR’{CODE}’
例如:
VAR=XXX
awk -v var=$VAR ‘BEGIN{print var}’
XXX
awk ‘BEGIN{print “‘$VAR’”}’
XXX
4. 为什么OFS不起作用?
先看一个例子:
echo ‘aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd’ |awk -v OFS=”|” ‘{print $0}’
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
上面的例子中OFS为什么没有生效呢,原因是OFS指的是输出字段分隔符,所以必须对字段进行操作时OFS才会起作用,正确的方法应该是:
echo ‘aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd’ |awk -v OFS=”|” ‘{$1=$1;print $0}’
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
$1=$1这个action,是我们对awk撒的谎,目的就是为了使得OFS生效,除此之外,NF+=0也是常用的方法。
5. 同样的代码,别人运行成功,为什么我运行失败?
这个问题的原因很多,我这里列举两个最常见的,大家可以补充。
: awk版本引起的,如gawk中的一些扩展函数或变量,在nawk中没有,或是不同版本的(g/n)awk也会有差别,这样情况需要重新编写。
: 文本格式的问题,cat-A file查看一下,如果是,dos2unix应该可以解决。
注:书写错误也有可能哦
6. Awk 语句中可以使用{n,m}这样的正则么?
可以,使用方法:gawk — re-interval ,其它版本使用方法会有所不同,请大家补充
7. BEGIN 和END 到底是怎么一回事?
有时,对于新手可能也会是个问题。简单说下:
BEGIN {action} : 读取文本之前进行的操作。要避免类似下面的写法:
awk ‘BEGIN{ filename = FILENAME}’ file
# or:
awk ‘BEGIN{FS=”:”; for(i=2;i<=NF;i++) print $i}' file
如果BEGIN 模块中使用getline函数时,情况会有所不同:
cat file
1
2
3
4
5
awk 'BEGIN{while (getline <"file") print}' file
1
2
3
4
5
END {action}:
它在整个输入文件处理完成后被执行,同样无法对文本进行任何操作,如匹配某个pattern执行action。
8. print,printf 和sprintf?
print:为一般的打印
printf:可以定义打印格式
sprintf:可以完成和printf相同的功能,不同的是sprintf只能输出值,并不能完成打印的功能。
12楼-expert1补充::) print默认有个换行\n,
而printf没有,当然它和C语言的printf类似(awk本是c的近亲),能打印各种格式,但默认没有换行。
例如:
awk 'BEGIN{var=123; print "var = " var}'
var = 123
awk 'BEGIN{var=123;printf "%s %5f\n", "var =",var}'
var = 123.000000
awk 'BEGIN{var=123;sprintf ("%s %5f\n", "var =",var)}'
awk ‘BEGIN{var1=123;var2=sprintf ("%5f",var1); print "var2 =" var2}’
var2 = 123.000000
9. “a==b?c:d” ?
这个是一个if语句的简写,即conditional expression1 ? expression2: expression3;完整写法为:
if(a==b) {c} else {d}
10. awk ‘! a[$0]++’ 怎么理解?
这是一个非常经典的去重复项的awk语句,虽然短小,不过涉及到了不少知识点,下面一一解读:
:”!” 即非。
:a[$0],以$0为数据下标,建立数组a
:a[$0]++,即给数组a赋值,a[$0]+=1
:那么组合起来,awk是怎么执行!a[$0]++的呢?我用一个实际例子来解释:
cat file
111
222
111
222
333
awk ‘{print a[$0],!a[$0]++,a[$0],!a[$0],$0}’ file
1 1 0 111
1 1 0 222
1 0 2 0 111
1 0 2 0 222
1 1 0 333
原来,第一个a[$0]的值为空,所以!a[$0]++是先作判断,结果为1(非空为真,即为1),再作数组赋值a[$0]++。这也就是为什么前面的!a[$0]++并不一定等于后面的!a[$0]。
awk ‘++a[$0]==1’ 和上面的代码作用一样,你理解了么?
11. 如何打印单双引号?
awk ‘BEGIN {print “single quote –> ‘\””;print “double quote –> \”" }’
single quote –> ‘
double quote –> ”
更可靠的的方法如Tim所示:
awk ‘BEGIN {print “single quote –> 47″;print “double quote –> 42″ }’
复制代码
12. awk 语句中多个{}是怎么执行的?
还是用个例子来说明:
cat file
1
2
3
4
5
awk ‘$1==3{printf “|| “$0}{printf ” @@ “$0}{print $0}’ file # 这个语句中包含三个action
@@ 11 # 判断$1==3?否;执行 action {printf ” @@ “$0};执行 action {print $0}
@@ 22 # 判断$1==3?否;执行 action {printf ” @@ “$0};执行 action {print $0}
|| 3 @@ 33 # 判断$1==3?是,执行{print “|| “$0}; 执行 action {printf ” @@ “$0};执行 action {print $0}
@@ 44 # 判断$1==3?否;执行 action {printf ” @@ “$0};执行 action {print $0}
@@ 55 # 判断$1==3?否;执行 action {printf ” @@ “$0};执行 action {print $0}
这样可以清楚的看出,awk是一行一行读取文本,然后按照代码的前后顺序执行。但如果action中包含next或exit时,有所不同:
awk ‘$1==3{printf “|| “$0;next}{printf “@@ “$0}{print $0}’ file
@@ 11
@@ 22
|| 3@@ 44
@@ 55
awk ‘$1==3{printf “|| “$0;exit}{printf “@@ “$0}{print $0}’ file
@@ 11
@@ 22
|| 3