linux提供了很多文本处理的屠龙刀,awk就是其中的佼佼者,称为一门面向文本的编程语言也不为过(awk中可以定义变量、进行运算,处理分支条件等等)。
如果早点学会awk,财务系统就不会写的这么费劲了,直接导出一份csv,写写awk脚本就好。
执行流程
完整的awd命令,可以由BEGIN BODY END三部分组成,其中BEGIN和END只会在awk执行前后运行一次,而BODY部分会每行不断处理。
Example
下面是几个几个awk的例子
1 2 3 4 5 6 7 8 9 10
| awk -F: '{print $1}' /etc/passwd
awk –F: 'BEGIN{printf "username\n-------\n"}\ { print $1 }\ END {print "----------" }' /etc/passwd
awk –F: 'BEGIN {print "UID"} {print $3}' /etc/passwd
|
我们以awk -F: '{print $1}' /etc/passwd
为例来看分析一下
- -F:指定了以:作为分隔符
- ‘{ print $1 }’ 表示输出第一个
- /etc/passwd是输入的文件
这个命令会输出
1 2 3 4 5 6 7 8 9 10 11
| root daemon bin sys sync games man lp mail news ...
|
指定分隔符
默认的输入分隔符是空格,可以通过-F选项来指定输入字段分隔符,例如
1 2 3
| awk -F: '{print $2}' /etc/passwd
awk -F, '{print $2}' example.csv
|
也可以通过设置OFS变量来指定输出字段分隔符
1
| awk -F, 'BEGIN {OFS=":"} {print $2, $3}' employee.txt
|
当一行容纳了多组数据时,awk允许你指定数据之间的分隔符,输入记录分隔符
1
| awk -F, 'BEGIN { RS=":" } {print $2}' employee-one-line.txt
|
在输出时,记录直接允许指定输出记录分隔符
1
| awk 'BEGIN {FS=",";ORS="\n---\n"} {print $2,$3}' employee.txt
|
$1、$2这样的变量代表分割后的字符串数组中的位置, $0代表整行
Pattern Maching
当然,我们可以只处理一行中的某些部分,通过正则实现
1 2 3 4 5 6 7 8 9 10 11
|
awk -F, '/Manager/ {print $2, $3}' employee.txt
|
awk变量、运算
一旦涉及变量定义这种比较复杂的功能,我就偏向于写awk脚本,然后awk -f xx.awk somefile
这样来执行,常见的数学操作(+-*/%,++ –)都支持。
1 2 3 4 5 6 7 8 9 10 11
| BEGIN { FS=","; total=0; } { print $2 "'s salary is: " $4; total+=$4; } END { print "----\nTotal Company Salary=$" total; }
|
awk比较
awk支持以下比较
可以理解成sql中的where条件
1 2 3 4
| awk -F, '$5<=5' items.txt awk -F "," '$4 < 900 || $5 <= 5' items.txt awk -F ':' '$3 > maxuid { maxuid = $3; maxline = $0 } END { print maxuid,maxline }' /etc/passwd awk -F ':' '$3 >= 100 && $NF ~ /\/bin\/sh/ ' /etc/passwd
|
awk控制流
awk支持if,if\else,while、do-while都常见控制流,for(;;)当然也不在话下,连break、continue、exit都有哦。
1 2 3 4 5 6 7 8 9 10 11 12
| cat dowhile.awk
{ i=2; total=0; do { total = total + $i; i++; } while(i<=NF) print "Item",$1,":",total,"quantities sold"; }
|
1
| echo "1 2 3 4" | awk '{ for (i=1;i<=NF;i++) total = total + $i } END { print total }'
|
awk关联数组
没错,这个就是lua中的关联数组的概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| $ cat array-assign.awk BEGIN { item[101]="HD Camcorder"; item[102]="Refrigerator"; item[103]="MP3 Player"; item[104]="Tennis Racket"; item[105]="Laser Printer"; item[1001]="Tennis Ball"; item[55]="Laptop"; item["na"]="Not Available"; print item["101"]; print item[102]; print item["103"]; print item[104]; print item["105"]; print item[1001]; print item["na"]; } $ awk -f array-assign.awk HD Camcorder Refrigerator MP3 Player Tennis Racket Laser Printer Tennis Ball Not Available
|
数组遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| $ cat array-for-loop.awk BEGIN { item[101]="HD Camcorder"; item[102]="Refrigerator"; item[103]="MP3 Player"; item[104]="Tennis Racket"; item[105]="Laser Printer"; item[1001]="Tennis Ball"; item[55]="Laptop"; item["no"]="Not Available"; for(x in item) print item[x] } $ awk -f array-for-loop.awk Not Available Laptop HD Camcorder Refrigerator MP3 Player Tennis Racket Laser Printer Tennis Ball
|
数组删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| $ cat array-delete.awk BEGIN { item[101]="HD Camcorder"; item[102]="Refrigerator"; item[103]="MP3 Player"; item[104]="Tennis Racket"; item[105]="Laser Printer"; item[1001]="Tennis Ball"; item[55]="Laptop"; item["no"]="Not Available"; delete item[102] item[103]="" delete item[104] delete item[1001] delete item["na"] for(x in item) print "Index",x,"contains",item[x] } $ awk -f array-delete.awk Index no contains Not Available Index 55 contains Laptop Index 101 contains HD Camcorder Index 103 contains Index 105 contains Laser Printer
|
awk支持的功能还有很多,这里不一一介绍,总之,凡是文本数据处理,用awk就没错了!
参考
https://www.thegeekstuff.com/sed-awk-101-hacks-ebook/