[转帖] 原来awk真是神器啊

原来,awk,真是,神器 · 浏览次数 : 0

小编点评

id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name id,name

正文

https://www.cnblogs.com/codelogs/p/16060082.html

 

简介#

刚开始入门awk时,觉得awk很简单,像是一个玩具,根本无法应用到工作之中,但随着对awk的了解不断加深,就会越发觉得这玩意的强大,大佬们称其为上古神器,绝不是空穴来风。
这也可以说明,一些热门的技术知识点,如果你觉得它不过如此,那绝对是你对它的掌握不够深入,而不是它没啥用。

基本语法#

awk基本语法如下:

awk 'BEGIN{//your code} pattern1{//your code} pattern2{//your code} END{//your code}'
  1. BEGIN部分的代码,最先执行
  2. 然后循环从管道中读取的每行文本,如果匹配pattern1,则执行pattern1的代码,匹配pattern2,则执行pattern2中的代码
  3. 最后,执行END部分的代码
    如下所示,分别求奇数行与偶数行的和:
$ seq 1 5
1
2
3
4
5

$ seq 1 5|awk 'BEGIN{print "odd","even"} NR%2==1{odd+=$0} NR%2==0{even+=$0} END{print odd,even}'
odd even
9 6
  1. seq 1 5用来生成1到5的数字。
  2. awk先执行BEGIN块,打印标题。
  3. 然后第1行尝试匹配NR%2==1这个pattern,其中NR为awk的内置变量,表示行号,$0为awk读到的当前行数据,显然匹配NR%2==1,则执行里面的代码。
  4. 然后第1行尝试匹配NR%2==0这个pattern,显然不匹配。
  5. 然后第2行、第3行...,一直到最后一行,都执行上面两步。
  6. 最后执行END块,将前面求和的变量打印出来,其中9=1+3+56=2+4
    这个程序还可以如下这样写:
seq 1 5|awk 'BEGIN{print "odd","even"} {if(NR%2==1){odd+=$0}else{even+=$0}} END{print odd,even}'

这里使用了if语句,实际上awk的程序语法与C是非常类似的,所以awk也有else,while,for,break,continue,exit

另外,可以看到,awk程序在处理时,默认是一行一行处理的,注意我这里说的是默认,并不代表awk只能一行一行处理数据,接下来看看awk的分列功能,可通过-F选项提供,如下:

$ paste <(seq 1 5) <(seq 6 10) -d,
1,6
2,7
3,8
4,9
5,10

$ paste <(seq 1 5) <(seq 6 10) -d, |awk -F, '{printf "%s\t%s\n",$1,$2}'
1       6
2       7
3       8
4       9
5       10

这个例子用-F指定了,,这样awk会自动将读取到的每行,使用,分列,拆分后的结果保存在$1,$2...中,另外,你也可以使用$NF,$(NF-1)来引用最后两列的值,不指定-F时,awk默认使用空白字符分列。
注意这里面的printf "%s\t%s\n",$1,$2,printf是一个格式化打印函数,其实也可以写成printf("%s\t%s\n", $1, $2),只不过awk中函数调用可以省略括号。

上面已经提到了NR这个内置变量,awk还有如下内置变量

内置变量作用
FS 与-F功能类似,用来分列的,不过FS可以是正则表达式,默认是空白字符
OFS 与FS对应,指定print函数输出时的列分隔符,默认空格
RS 记录分隔符,默认记录分隔符是\n
ORS 与RS对应,指定print函数输出时的记录分隔符,默认\n

用2个例子体会一下:

$ echo -n '1,2,3|4,5,6|7,8,9'|awk 'BEGIN{RS="|";FS=","} {print $1,$2,$3}'
1 2 3
4 5 6
7 8 9
$ echo -n '1,2,3|4,5,6|7,8,9'|awk 'BEGIN{RS="|";FS=",";ORS=",";OFS="|"} {print $1,$2,$3}'
1|2|3,4|5|6,7|8|9,

总结:awk数据读取模式,总是以RS为记录分隔符,一条一条记录的读取,然后每条记录按FS拆分为字段。

再看看这个例子:

$ seq 1 5|awk '/^[1-4]/ && !/^[3-4]/'
1
2
$ seq 1 5|awk '$0 ~ /^[1-4]/ && $0 !~ /^[3-4]/{print}'
1
2
$ seq 1 5|awk '$0 ~ /^[1-4]/ && $0 !~ /^[3-4]/{print $0}'
1
2

可以看到:

  1. awk中pattern部分可以直接使用正则表达式,而且可以使用&&,||,!这样的逻辑运算符.
  2. 如果正则表达式没有指定匹配变量,默认对$0执行匹配,所以awk '/regex/'直接就可以等效于grep -E 'regex'.
  3. 另外pattern后面的代码部分如果省略的话,默认打印$0.
  4. print函数如果没有指定参数,也默认打印$0.
  5. 另外,一定注意awk中的正则表达式不支持\d,匹配数字请使用[0-9],因为linux中正则语法分BRE,ERE,PCRE,而awk支持的是ERE.

到这里,awk基本语法就差不多讲完了,接下来会介绍一些常用的场景。

查找与提取#

示例数据如下,也是用awk生成的:

$ seq 1 10|awk '{printf "id=%s,name=person%s,age=%d,sex=%d\n",$0,$0,$0/3+15,$0/6}'|tee person.txt
id=1,name=person1,age=15,sex=0
id=2,name=person2,age=15,sex=0
id=3,name=person3,age=16,sex=0
id=4,name=person4,age=16,sex=0
id=5,name=person5,age=16,sex=0
id=6,name=person6,age=17,sex=1
id=7,name=person7,age=17,sex=1
id=8,name=person8,age=17,sex=1
id=9,name=person9,age=18,sex=1
id=10,name=person10,age=18,sex=1

然后用awk模拟select id,name,age from person where age > 15 and age < 18 limit 4这样SQL的逻辑,如下:

$ cat person.txt |awk 'match($0, /^id=(\w+),name=(\w+),age=(\w+)/, a) && a[3]>15 && a[3]<18 { print a[1],a[2],a[3]; if(++limit >= 4) exit 0}'
3 person3 16
4 person4 16
5 person5 16
6 person6 17
  1. 首先使用match函数以及正则表达式的捕获组功能,将id,name,age的值提取到a[1],a[2],a[3]中.
  2. 然后a[3]>15 && a[3]<18即类似SQL中age > 15 and age < 18的功能.
  3. 然后打印a[1],a[2],a[3],类似SQL中select id,name,age的功能.
  4. 最后,如果打印条数到达4条,退出程序,即类似limit 4的功能.

简单统计分析#

awk可以做一些简单的统计分析任务,还是以SQL为例。
select age,sex,count(*) num, group_concat(id) ids from person where age > 15 and age < 18 group by age,sex这样的统计SQL,用awk实现如下:

$ cat person.txt |awk '
    BEGIN{
        printf "age\tsex\tnum\tids\n"
    }
    match($0, /^id=(\w+),name=(\w+),age=(\w+),sex=(\w+)/, a) && a[3]>15 && a[3]<18 { 
        s[a[3],a[4]]["num"]++; 
        s[a[3],a[4]]["ids"] = (s[a[3],a[4]]["ids"] ? s[a[3],a[4]]["ids"] "," a[1] : a[1])
    } 
    END{
        for(key in s){
            split(key, k, SUBSEP);
            age=k[1];
            sex=k[2];
            printf "%s\t%s\t%s\t%s\n",age,sex,s[age,sex]["num"],s[age,sex]["ids"]
        }
    }'
age     sex     num     ids
17      1       3       6,7,8
16      0       3       3,4,5

awk代码稍微有点长了,但逻辑还是很清晰的。

  1. BEGIN中打印标题行.
  2. match获取出id,name,age,sex,并过滤age>15且age<18的数据,然后将统计结果累计到s这个关联数组中。你可以把s这个关联数组想象中map,然后只是有两级key而已。(注意在awk中,拼接字符串使用空格即可,并不像java中使用+号).
  3. 最后END块中,遍历s这个关联数组,注意,类似s[a[3],a[4]]这样,在awk中是一个key,awk会使用SUBSEP这个变量将a[3],a[4]拼接起来,需要split(key, k, SUBSEP),将key按SUBSEP拆分到k中,SUBSEP默认是\034文件分隔符.

处理csv#

csv是以一行为一条记录,以,号分隔为列的数据格式,awk天然适合处理csv这样的数据,但在列值中本身存在,号时,只使用-F就不行了,这时可以使用FPAT,如下:

$ echo 'aa,"bb,cc",dd'|gawk 'BEGIN { FPAT = "[^,]+|\"[^\"]+\"" } { print $3 }'
dd

FPAT变量用于提取字段值,这里指定为正则表达式,只不过这个正则表达式可以匹配类似aa"bb,cc"这种数据.

按段拆分记录#

awk可以按段拆分记录,什么是段呢,看一下ifconfig的输出,如下:

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.73.125  netmask 255.255.240.0  broadcast 172.17.79.255
        inet6 fe80::215:5dff:fe4c:c155  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:4c:c1:55  txqueuelen 1000  (Ethernet)
        RX packets 35008  bytes 5829277 (5.8 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4435  bytes 7152614 (7.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 82  bytes 4100 (4.1 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 82  bytes 4100 (4.1 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ifconfig的输出中,eth0与lo的数据使用空行间隔开了,像这种,用空行间隔的内容,其中eth0部分是一个段,lo部分也是一个段,而在awk中,RS=""即表示按段拆分记录,所以获取eth0网卡ip地址的方法是:

$ ifconfig|awk -v RS="" '/^eth0/{print $6}'
172.17.73.125

这里用-v RS=""来设置RS变量,与在BEGIN中效果是一样的,-v name=var是shell向awk内部传递变量的一种方法。

另外,java中jstack获取的线程栈的内容,也是以空行分段输出的,用awk来处理也很简单,比如,我们只看目前与mysql有关的线程栈,如下:

$ jstack `pgrep java`|awk -v RS="" '/mysql/'
"Abandoned connection cleanup thread" #18 daemon prio=5 os_prio=0 tid=0x00007fbb893d0000 nid=0xd75 in Object.wait() [0x00007fbb586ad000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
        - locked <0x00000000e160ee38> (a java.lang.ref.ReferenceQueue$Lock)
        at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:40)

到这里,我们不难想到,用awk来搜索异常日志,其实比grep更方便,比如java中如下的错误日志:

$ cat app_demo.log
[2020-12-23 20:12:51] [app_demo] [172.29.128.1] [INFO] [RMI TCP Connection(7)-172.29.128.1] {"logger":"o.a.catalina.core.ContainerBase.[Tomcat].[localhost].[/]","msg":"Initializing Spring DispatcherServlet 'dispatcherServlet'"}
[2020-12-23 20:12:51] [app_demo] [172.29.128.1] [INFO] [RMI TCP Connection(7)-172.29.128.1] {"logger":"org.springframework.web.servlet.DispatcherServlet","msg":"Initializing Servlet 'dispatcherServlet'"}
[2020-12-23 20:12:51] [app_demo] [172.29.128.1] [INFO] [RMI TCP Connection(7)-172.29.128.1] {"logger":"org.springframework.web.servlet.DispatcherServlet","msg":"Completed initialization in 26 ms"}
[2020-12-23 20:15:00] [app_demo] [172.29.128.1] [ERROR] [redisson-netty-1-6] {"logger":"org.redisson.client.handler.CommandsQueue","msg":"Exception occured. Channel: [id: 0x43577278, L:/127.0.0.1:61888 - R:localhost/127.0.0.1:22122]
    java.io.IOException: 远程主机强迫关闭了一个现有的连接。
        at sun.nio.ch.SocketDispatcher.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:192)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
        at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
        at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
        at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)"}

# 使用grep直接搜索IOException,效果如下,看不到前后的调用栈了
$ cat app_demo.log |grep 'IOException'
    java.io.IOException: 远程主机强迫关闭了一个现有的连接。 

# grep可以使用-B -C指定匹配内容前面显示几行,后面显示几行,如grep -B 2 -C 10
# 效果如下,由于不知道线程栈有多深,-C有时会设置小了,有时又会设置大了
$ cat app_demo.log |grep -B2 -C10 'IOException'
[2020-12-23 20:12:51] [app_demo] [172.29.128.1] [INFO] [RMI TCP Connection(7)-172.29.128.1] {"logger":"org.springframework.web.servlet.DispatcherServlet","msg":"Completed initialization in 26 ms"}
[2020-12-23 20:15:00] [app_demo] [172.29.128.1] [ERROR] [redisson-netty-1-6] {"logger":"org.redisson.client.handler.CommandsQueue","msg":"Exception occured. Channel: [id: 0x43577278, L:/127.0.0.1:61888 - R:localhost/127.0.0.1:22122]
    java.io.IOException: 远程主机强迫关闭了一个现有的连接。
        at sun.nio.ch.SocketDispatcher.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:192)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
        at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
        at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
        at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)"

# 使用awk,RS='\n\\S',效果如下,简直完美!
$ cat app_demo.log |awk -v RS='\n\\S' '/IOException/'
2020-12-23 20:15:00] [app_demo] [172.29.128.1] [ERROR] [redisson-netty-1-6] {"logger":"org.redisson.client.handler.CommandsQueue","msg":"Exception occured. Channel: [id: 0x43577278, L:/127.0.0.1:61888 - R:localhost/127.0.0.1:22122]
    java.io.IOException: 远程主机强迫关闭了一个现有的连接。
        at sun.nio.ch.SocketDispatcher.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
        at sun.nio.ch.IOUtil.read(IOUtil.java:192)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
        at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
        at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
        at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:648)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:583)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:500)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:462)
        at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)"}

这里的RS='\n\\S'是一个正则表达式,记录分隔符为换行符后面带一个非空白符。

最后,指定RS='^$'可以将数据一次性的读取到$0中,这也是一个常用的小技巧,因为^$显然无法匹配任何字符,这样awk就会将所有数据读取到一条记录中了。
如下,将多行数据用,拼接为一行数据:

$ seq 1 10|awk -v RS='^$' '{gsub(/\n/, "," , $0);print $0}'
1,2,3,4,5,6,7,8,9,10,

范围匹配#

awk中另一个比grep强的地方,就是awk可以使用范围过滤数据,而grep只能使用正则,比如我们要搜索2021-01-04 23:33:402021-01-04 23:34:16的日志:

# 搜索2021-01-04 23:33:40到2021-01-04 23:34:16的日志,前提是这两个时间在日志中都存在,因为awk是在遇到2021-01-04 23:33:40后,开启打印,直到遇到2021-01-04 23:34:16又关闭打印
cat app.log|awk '/2021-01-04 23:33:40/,/2021-01-04 23:34:16/'

# 另一种更有效的方式
cat app.log|awk 'match($0,/^\[([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})\]/,a){
        if(a[1]>="2021-01-07 12:26:43") 
          print $0; 
        if(a[1]>"2021-01-07 12:26:56") exit
    }'

多文件join处理#

awk还可以实现类似SQL中的join处理,求交集或差集,如下:

$ cat user.txt
1 zhangsan
2 lisi
3 wangwu
4 pangliu

$ cat score.txt
1 86
2 57
3 92

# 类似 select a.id,a.name,b.score from user a left join score b on a.id=b.id
# 这里FNR是当前文件中的行号,而NR一直是递增的,所以对于第一个score.txt,NR==FNR成立,第二个user.txt,NR!=FNR成立
$ awk 'NR==FNR{s[$1]=$2} NR!=FNR{print $1,$2,s[$1]}' score.txt user.txt
1 zhangsan 86
2 lisi 57
3 wangwu 92
4 pangliu

# 当然,也可以直接使用FILENAME内置变量,如下
$ awk 'FILENAME=="score.txt"{s[$1]=$2} FILENAME=="user.txt"{print $1,$2,s[$1]}' score.txt user.txt

# 求差集,打印user.txt不在score.txt中的行
$ awk 'FILENAME=="score.txt"{s[$1]=$2} FILENAME=="user.txt" && !($1 in s){print $0}' score.txt user.txt
4 pangliu

awk常用函数#

函数名说明示例
sub 替换一次 sub(/,/,"|",$0)
gsub 替换所有 gsub(/,/,"|",$0)
match 匹配,捕获内容在a数组中 match($0,/id=(\w+)/,a)
split 拆分,拆分内容在a数组中 split($0,a,/,/)
index 查找字符串,返回查找到的位置,从1开始 i=index($0,"hi")
substr 截取子串 substr($0,1,i)substr($0,i)
tolower 转小写 tolower($0)
toupper 转大写 toupper($0)
srand,rand 生成随机数 BEGIN{srand();printf "%d",rand()*10}

替换其它文本处理命令#

grep

命令说明awk实现
grep 'regex' 过滤记录 awk '/regex/'

sed

命令说明awk实现
sed -n '/regex/ p' 过滤记录 awk '/regex/'
sed -n '1,5 p' 显示前5行 awk 'NR<=5'
sed '/1~2/ s/hello/hi/g' 奇数行所有hello替换为hi awk 'NR%2==1{gsub(/hello/,"hi",$0);print $0}'
sed '/regex/ d' 删除匹配行 awk '!/regex/'
sed '1 i\id,name' 第1行插入一行标题 awk '{if(NR==1) print "id,name"; print $0}'
sed '1 a\id,name' 第1行后面添加一行 awk '{print $0; if(NR==1) print "id,name"}'
sed '1 c\id,name' 修改第1行整行内容 awk '{if(NR==1){print "id,name"}else{print $0}}'

可以发现,sed其实是awk程序在某些场景的固化,因为awk程序类似awk 'pattern{}',而sed程序类似sed 'pattern action',action就是p,s,d,i,a,c这些动作,而这些动作对应awk固化在{}中的代码。

然后grep是进一步的场景固化,它只支持正则过滤。

tr

命令说明awk实现
tr -d '\n' 删除换行符 awk -v RS='^$' '{gsub(/\n/, "" , $0);print $0}'
tr -s ' ' 压缩多个空格为一个,awk的这个实现有点hack awk '{$1=$1;print $0}'
tr [a-z] [A-Z] 转大写 awk '{print toupper($0)}'

cut

命令说明awk实现
cut -d, -f2 ,拆分取第2个字段 awk -F, '{print $2}'

head

命令说明awk实现
head -n10 取前10行 awk '{print $0;if(++n >= 10) exit 0}'

tail

命令说明awk实现
tail -n10 取倒数10行 这个直接用awk实现有点长,没必要,可以用tac辅助
`tac test.log

wc

命令说明awk实现
wc -l 统计文件行数 awk 'END{print NR}'

uniq

命令说明awk实现
uniq -c 分组计数 awk '{s[$0]++} END{for(k in s){print s[k],k}}'

总结#

awk其本身就是为文本处理而生的,不太复杂的临时性的文本处理分析,第一个想到的就应该是它!
后面,我再总结一下shell本文处理的常见技巧,作为本篇的补充。

往期内容#

不容易自己琢磨出来的正则表达式用法
好用的parallel命令
还在胡乱设置连接空闲时间?
常用网络命令总结
使用socat批量操作多台机器

与[转帖] 原来awk真是神器啊相似的内容:

[转帖] 原来awk真是神器啊

https://www.cnblogs.com/codelogs/p/16060082.html 简介# 刚开始入门awk时,觉得awk很简单,像是一个玩具,根本无法应用到工作之中,但随着对awk的了解不断加深,就会越发觉得这玩意的强大,大佬们称其为上古神器,绝不是空穴来风。这也可以说明,一些热门的

[转帖]Shell三剑客之awk

目录 awk简述awk的工作过程awk的工作原理awk的基本格式及其内置变量getline文本内容匹配过滤打印对字段进行处理打印条件判断打印awk的三元表达式与精准筛选用法awk的精准筛选:awk的分隔符用法指定输出的分隔符awk结合数组运用面试题 awk简述 在 Linux/UNIX 系统中,aw

[转帖]Linux AWK工作原理

https://www.cnblogs.com/yeyuzhuanjia/p/13967513.html 本篇文章我们主要为大家介绍 AWK 是如何工作的。 AWK 工作流程可分为三个部分:1.读输入文件之前执行的代码段(由BEGIN关键字标识)。2.主循环执行输入文件的代码段。3. 读输入文件之后

[转帖]《AWK程序设计语言》笔记(1)—— AWK入门与简单案例

原文为 《The AWK Programming Language》,GitHub上有中译版,不过有些内容翻译的比较奇怪,建议跟原版对照着看 https://github.com/wuzhouhui/awk 本篇的小案例基本均基于文件 emp.data,三个字段分别为:员工名、每小时工资、工作时长,

[转帖]awk高级企业级使用案例

https://www.jianshu.com/p/e36176ad3c06 一、背景: 以某物联网企业,传感器设备实时数据消费服务(Kafka-consumer)为例,调试筛选处理耗时的主题。 1. 原始日志格式(logback输出的): 2018-07-11 11:49:22.413 INFO

[转帖] Linux文本命令技巧(上)

Linux文本命令技巧(上) 原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。 简介# 前一篇我介绍了awk,这是一个全能的文本处理神器,因为它本身就是一门编程语言了,但对于很多场景,使用Linux预设的一些文本处理命令,会更方便快捷,如grep、sed等。本篇就来介绍

[转帖] q命令-用SQL分析文本文件

https://www.cnblogs.com/codelogs/p/16060830.html 原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。 简介# 在Linux上分析文本文件时,一般会使用到grep、sed、awk、sort、uniq等命令,但这些命令都有一定的

[转帖] jq命令用法总结

https://www.cnblogs.com/codelogs/p/16324928.html 原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。 简介# 如果说要给Linux文本三剑客(grep、sed、awk)添加一员的话,我觉得应该是jq命令,因为jq命令是用来处

[转帖]原来这就是帕金森时间定律,很多人竟然还不知道,为生命加快脚步

https://baijiahao.baidu.com/s?id=1673564759668576951&wfr=spider&for=pc 2020-07-29 23:15名师,皖蒙城县双涧中学,优质文化领域创作者,活力创作者 关注 在别人做一件事的时间里,你能够做几件事?是更多还是更少?事半功倍

[转帖]LVS 20倍的负载不均衡,原来是内核的这个Bug

https://plantegg.github.io/2019/07/19/%E5%B0%B1%E6%98%AF%E8%A6%81%E4%BD%A0%E6%87%82%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1--%E8%B4%9F%E8%BD%BD%E5%9D%87%E