awk 笔记
Table of Contents
1. awk 匹配模式
语法:
匹配 {动作}
{ BEGIN {print "hello world"} } # 整行匹配 { /root/ {print $0} }
1.1. 正则
1.1.1. 提取正则匹配的结果
echo abc123 | awk 'match($1, /[0-9]+/, a){print a[0]}
2. 变量定义
2.1. 内置变量
FNR,当前文件的所在行。例,打印某一样的数据:
awk -F: 'FNR == 3{print}' /etc/passwd
NR:记录当前共读了多少行。
FNR 和 NR 在多文件情况下能区别出来:
awk '{print FNR}' /etc/passwd /etc/hosts awk '{print NR}' /etc/passwd /etc/hosts
NF,当前行的列数。例,找出少于 4 列的行:
{print NF}
例,打印最后一列:
{print $NF}
例,行列互换,member.txt 内容如下:
name lx blog www.shellcodes.org github http://github.com/1u4nx
将它转为如下格式:
name blog github lx www.shellcodes.org http://github.com/1u4nx
实现代码如下:
{ for (i=1; i<=NF; i++) { data[i, NR] = $i } } END { for (i=1; i<=NF; i++) { for(n=1; n<=NR; n++) { printf data[i, n] " " } print "" } }
2.2. 和 shell 交互
例,正则使用 shell 中的变量
for i in {00..05} do awk '$2~/2016-04-07<SP>'$i'/' web.log done
3. 列操作
3.1. 列引用
for (i=0; i<3; i++) { print $(i) # 引用第 i 列的数据 }
3.2. 排除某列
例,打印数据,并排除第一列:
{
$1=null;
print
}
3.3. 以列值为文件名,将相同列值的行输出到同一文件
比如某个单日志文件中记录列多个域名的日志,需要将域名输出到各自的文件中:
# 假设第 5 列是域名 awk '{print >> $5}' website.log
4. 数组
遍历数组方法 1:
awk -F: '{users[FNR]=$1};END{len=length(users);for (i=0;i<=len;i++) {print users[i]}}' /etc/passwd
遍历数组方法 2:
awk -F: '{users[$1]=1};END{for (user in users) {print user}}' /etc/passwd
例,有一个日志文件,还有一个 IP 列表文件,需要从日志中按 IP 列表导出相应的日志:
BEGIN { while (getline < "IP列表.txt") { ips[$0]=1; } while (getline < "日志文件") { split($0, ft, " "); if(ips[ft[6]]) { print $0; } } }
去重:
awk '!x[$0]++' 文件名
5. 函数
gsub,正则替换:
# 例,手机号打码 echo 'user=lu4nx&phone=13800138000' | awk 'gsub(/phone=[0-9]{11}/, "phone=***")'
6. 输出重定向
重定向输出
基本语法:
print DATA > file print DATA >> file # 追加
例,一个 Web 日志文件包含了多个子域名的请求记录,按主域将其重定向到不同文件中:
awk '{if($6~/abc.com/){print >> "abc.log"} else { print >> "cde.log"}}' web.log
管道
基本语法:
print DATA | command
例 1,调用外部脚本查询 Web 日志 IP 列的地理位置:
awk '{print $1 | "python3 query_ip.py"}' web.log
例 2,更复杂一点,将外部命令输出的结果存储到变量中:
awk '{cmd="python query_ip.py "$1; cmd | getline result; close(cmd);print $1,result}' web.log
双向通信
使用“|&”与外部命令建立双向通信的连接,这样就能将外部命令的输出存储到变量中。可以将上面的例子 2 改为双向通信:
awk '{ cmd="python query_ip.py "$1; print $1 |& cmd; # 通过双向管道将参数传递到外部程序 close(cmd, "to"); # 关闭单项管道 cmd |& getline result; # 用 getline 将外部输出结果保存到变量 result 中 print $1,result; close(cmd) }'