欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

深入浅出认识awk

时间:2023-06-30
概述

awk是Unix-like系统常用的文本处理工具。

其功能可总结为:将输入文本切成表格,通过行筛选、字段重组、跨行上下文、逻辑判断等灵活组合,实现定制化输出。

简单示例

通过简单示例,建立初步印象。
输入文件:coord_list

115.631449,33.110324;115.638022,33.1160350.0,0.0;0.0,0.0115.150937,40.549179;115.157529,40.554885110.029599,27.578549;110.036011,27.5848270.0,0.0;0.0,0.0

命令:

awk -F'[,;]' '$1!=0 {print $3"|"$4}' coord_list

其中

参数: -F'[,;]' 指定正则做为字段分隔符(单个逗号或分号);条件: $1!=0 第一个字段必须不等于0;动作: {print $3"|"$4} 输出第三和第四个字段,中间以竖线分隔。

输出:

115.638022|33.116035115.157529|40.554885110.036011|27.584827

命令结构 参数部分

常用的有

-F 指定字段切分的分隔符,默认为空格。可以指定单个字符,比如 -F, 或 -F: 或 -F't' ;如果指定多个字符,则视为正则表达式,比如 -F' |t' 或 -F's+' 脚本部分

完整形态的脚本模式:

'BEGIN{前置动作} 行操作 END{后置动作}'

其中

BEGIN{前置动作}:可选,在整个文件处理开始前执行,一般会 修改配置、定义全局变量、打印表头等行操作(for each line):可选,每行数据执行一次,具体模式见下文END{后置动作}:可选,在整个文件处理结束后执行,一般会 处理Buffer中的残留内容

行操作的具体模式有

'条件':对满足条件的行,执行隐含动作:直接打印当前行(等价于 '条件 {print $0}' )'{动作}':对所有行,执行动作'条件 {动作}':对满足条件的行,执行动作'条件1 {动作1} 条件2 {动作2}':对满足条件1的行,执行动作1;对满足条件2的行,执行动作2 脚本使用案例 案例1:包含完整命令结构的简单示例【对前5个数字求平均】

输入文件:top10

美国,72958690印度,39799202巴西,24134946法国,16800913英国,15953685俄罗斯,11241109土耳其,11014152意大利,10001344西班牙,9280890德国,8808107

命令:

awk -F, 'BEGIN{sum=0;cnt=0} NR<=5 {sum+=$2;cnt++} END{print sum/cnt/10000"万"}' top10

其中

NR<=5:筛选前5行。NR为awk内置变量,含义为当前行号(Number of Records)

输出:

3392.95万

案例2:使用全局变量的简单示例【构造进程pid关系链】

输入文件:ps(来自 ps -ef 输出结果,已脱敏)

UID PID PPID C STIME TTY TIME CMDroot 1 0 0 Jan17 ? 00:36:47 /usr/bin/python /usr/lib/systemd/syste+root 444 1 0 Jan17 ? 00:00:08 /usr/sbin/sshd -Droot 448 1 0 Jan17 ? 00:00:05 /usr/sbin/crond -nroot 486 1 0 Jan17 ? 01:19:11 /home/staragent/bin/staragentdroot 880 0 0 Jan17 ? 00:33:10 /home/a/xxxxxxxxxx/xxxxxxxxxx -conf /h+root 924 880 0 Jan17 ? 00:00:00 [nslookup] root 2491 1 0 Jan17 ? 00:00:00 /usr/local/ilogtail/ilogtailroot 2493 2491 0 Jan17 ? 00:43:06 /usr/local/ilogtail/ilogtailroot 4430 0 0 Jan17 ? 00:00:00 nginx: master process /opt/xxxxxx/xxxx+root 16803 0 0 11:41 ? 00:00:03 /usr/bin/xxxxxxxxxx --verbose=2 -f /us+root 63148 1 0 Jan19 ? 00:15:10 /home/staragent/plugins/xxxxxxxxxxxx/j+root 85570 444 0 17:26 ? 00:00:00 sshd: yizishou [priv]yizishou 85572 85570 0 17:26 ? 00:00:00 sshd: yizishou@pts/0yizishou 85573 85572 0 17:26 pts/0 00:00:00 -bashyizishou 90169 85573 0 17:50 pts/0 00:00:00 ps -efroot 200642 1 0 Jan18 ? 00:00:35 /usr/sbin/syslog-ng -F -p /var/run/sys+root 200654 1 0 Jan18 ? 00:02:43 /usr/lib/systemd/systemd-journaldroot 200963 1 1 Jan19 ? 01:36:22 /home/xxxxxxxxx/plugins/xxxxxxxxx/xxxx+

命令:

awk 'NR>1 {s=(m[$3]==null?$3:m[$3])"-"$2; m[$2]=s; print s}' ps

其中

NR>1:过滤掉表头行。NR为awk内置变量,含义为当前行号(Number of Records)m:awk的变量是免定义的,会根据用法自动推断类型并初始化。这里将m作为Map使用,初始化为空Map

输出:

0-10-1-4440-1-4480-1-4860-8800-880-9240-1-24910-1-2491-24930-44300-168030-1-631480-1-444-855700-1-444-85570-855720-1-444-85570-85572-855730-1-444-85570-85572-85573-901690-1-2006420-1-2006540-1-200963

案例3:跨行合并与还原的案例【Java栈整体筛选】

思路:将多行合并为一行,筛选后还原为多行
输入文件:stk(来自 jstack 输出结果,截取部分内容)

2022-01-25 11:18:57Full thread dump OpenJDK 64-Bit Server VM (25.242-b24 mixed mode):"process reaper" #38398 daemon prio=10 os_prio=0 tid=0x00002b4b4e019800 nid=0x256b6 waiting on condition [0x00002b4b2af7c000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park0(Native Method) - parking to wait for <0x00000000f820d960> (a java.util.concurrent.SynchronousQueue$TransferStack) at sun.misc.Unsafe.park(Unsafe.java:1038) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:216) at ..."Attach Listener" #479 daemon prio=9 os_prio=0 tid=0x00002b4b49613000 nid=0x1430f waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE..."Surrogate Locker Thread (Concurrent GC)" #4 daemon prio=9 os_prio=0 tid=0x00002b4b2b04a000 nid=0xf6c7 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00002b4b2b049000 nid=0xf6c6 in Object.wait() [0x00002b4b426ff000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x00000000f8038ed8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:287)"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00002b4b2b048000 nid=0xf6c5 in Object.wait() [0x00002b4b421d4000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000f8038f08> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)"main" #1 prio=5 os_prio=0 tid=0x00002b4b2b047000 nid=0xf6b8 in Object.wait() [0x00002b4b283b7000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000000f803ca80> (a io.netty.channel.AbstractChannel$CloseFuture) at java.lang.Object.wait(Object.java:502) at io.netty.util.concurrent.DefaultPromise.await(DefaultPromise.java:254) - locked <0x00000000f803ca80> (a io.netty.channel.AbstractChannel$CloseFuture) at io.netty.channel.DefaultChannelPromise.await(DefaultChannelPromise.java:129) at ......

命令:

awk '{ if(match($0,"^\s")==1) {s=s"@@"$0} else { if(s!="") {print s} s=$0 } } END{if(s!="") {print s}}' stk | grep 'java.lang.ref.Reference' | awk 'BEGIN{RS="n|@@"} {print $0}'

其中

前一句awk:将Java栈压缩为一行(以@@分隔,以便还原)

if(match($0,"^\s")==1):判断当前行是否以空白字符开头。如果true,则认为是跟随行,需要合并到上一行后面s:awk的变量是免定义的,会根据用法自动推断类型并初始化。这里将s作为String使用,初始化为空串s=s"@@"$0:将当前行拼接在变量s后面,以@@分隔 grep语句:在压缩的Java栈中筛选"java.lang.ref.Reference"后一句awk:将压缩的Java栈还原为多行

RS:是awk的内置变量,即行分隔符(Record Separator),默认为换行符nBEGIN{RS="n|@@"}:将行分隔符修改为正则表达式n|@@。即保留默认n的基础上,追认@@为换行符

输出:内容包含 java.lang.ref.Reference 的两个线程栈

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00002b4b2b049000 nid=0xf6c6 in Object.wait() [0x00002b4b426ff000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) - locked <0x00000000f8038ed8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:287)"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00002b4b2b048000 nid=0xf6c5 in Object.wait() [0x00002b4b421d4000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x00000000f8038f08> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

案例4:多文件关联的案例【维度文件(小)与数据文件(大)】

思路:将维度加载为内存字典,提供给数据文件查询
输入文件1:dict(行政区划代码)

110000,北京市110101,东城区110102,西城区110105,朝阳区110106,丰台区110107,石景山区110108,海淀区110109,门头沟区110111,房山区110112,通州区...

输入文件2:data(包含行政区划代码的地理数据,已脱敏)

341204,〇营,115.630000,33.110000420107,〇〇〇〇专卖店,114.380000,30.630000130705,〇〇〇〇道,115.150000,40.540000340521,〇〇〇〇(〇〇村店),118.820000,31.380000330523,〇〇〇〇〇〇(〇〇路店),119.660000,30.790000370781,〇〇〇衣(〇〇站),118.530000,36.690000513433,〇〇〇〇饭店,102.210000,28.550000652926,〇〇〇〇销售中心,81.860000,41.790000431202,〇〇〇〇特价处理,110.020000,27.570000110115,停车场(〇〇〇〇〇〇〇〇),116.430000,39.760000...

命令:

awk -F',' '{if(FILENAME=="dict"){m[$1]=$2}else{print m[$1]","$0}}' dict data

其中

FILENAME:是awk的内置变量,即当前行所在的文件名。注意,通过管道输入的数据不存在文件名

输出:附带行政区划名称的地理数据

颍泉区,341204,〇营,115.630000,33.110000青山区,420107,〇〇〇〇专卖店,114.380000,30.630000宣化区,130705,〇〇〇〇道,115.150000,40.540000当涂县,340521,〇〇〇〇(〇〇村店),118.820000,31.380000安吉县,330523,〇〇〇〇〇〇(〇〇路店),119.660000,30.790000青州市,370781,〇〇〇衣(〇〇站),118.530000,36.690000冕宁县,513433,〇〇〇〇饭店,102.210000,28.550000拜城县,652926,〇〇〇〇销售中心,81.860000,41.790000鹤城区,431202,〇〇〇〇特价处理,110.020000,27.570000大兴区,110115,停车场(〇〇〇〇〇〇〇〇),116.430000,39.760000...

如果要深入了解

提供几个方向,可自行学习:

awk命令参数awk支持的运算符awk内置函数(比如print/match等)awk内置变量(比如NR/NF/FILENAME等)

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。