在每个时间块之间添加空行

时间:2018-02-05 07:46:21

标签: bash awk sed

我的输入日志是一个表单:

system 2018-02-05 04:15:49 :: aaaaaaaaaaaaa  
system 2018-02-05 04:15:51 :: aaaaaaaaaaaaa  
system 2018-02-05 04:15:51 :: aaaaaaaaaaaaa  
system 2018-02-05 04:15:52 :: aaaaaaaaaaaaa  
system 2018-02-05 04:15:53 :: aaaaaaaaaaaaa  
system 2018-02-05 04:20:06 :: ccccccccccccc
system 2018-02-05 04:21:10 :: bbbbbbbbbbbbb
system 2018-02-05 04:21:10 :: ccccccccccccc
system 2018-02-05 04:21:10 :: ccccccccccccc
system 2018-02-05 04:21:10 :: ccccccccccccc
system 2018-02-05 04:23:49 :: bbbbbbbbbbbbb
system 2018-02-05 04:23:49 :: ccccccccccccc

并希望用空行分隔每个时间块。 上述输入的预期输出为:

system 2018-02-05 04:15:49 :: aaaaaaaaaaaaa

system 2018-02-05 04:15:51 :: aaaaaaaaaaaaa  
system 2018-02-05 04:15:51 :: aaaaaaaaaaaaa  

system 2018-02-05 04:15:52 :: aaaaaaaaaaaaa  

system 2018-02-05 04:15:53 :: aaaaaaaaaaaaa  

system 2018-02-05 04:20:06 :: ccccccccccccc

system 2018-02-05 04:21:10 :: bbbbbbbbbbbbb
system 2018-02-05 04:21:10 :: ccccccccccccc
system 2018-02-05 04:21:10 :: ccccccccccccc
system 2018-02-05 04:21:10 :: ccccccccccccc

system 2018-02-05 04:23:49 :: bbbbbbbbbbbbb
system 2018-02-05 04:23:49 :: ccccccccccccc

5 个答案:

答案 0 :(得分:6)

我们的想法是形成每条线都是唯一的键,在您的情况下它是$2$3(即在Awk的上下文第二和第三个空格分隔的列中)。

我们通过这种组合构建一个唯一键($2 $3),如果此组合与后续行不同,则在解析行时,我们会打印一个新行字符(也由特殊变量ORS表示或只在Awk中print ""。以下代码仅反映了

$ awk '($2 $3)!=p && NR>1 {print ""} {print; p=($2 $3)}' file
system 2018-02-05 04:15:49 :: aaaaaaaaaaaaa  

system 2018-02-05 04:15:51 :: aaaaaaaaaaaaa  
system 2018-02-05 04:15:51 :: aaaaaaaaaaaaa  

...

答案 1 :(得分:4)

另一个简短的 awk 方法:

awk 'NR>1 && !a[$2$3]++{ print "" }1' file
  • !a[$2$3]++ - 使用 date $2 time {{1}的连接检查唯一 datetime 值} values as array key

输出:

$3

答案 2 :(得分:2)

每个时间块的另一个awk方法

在您想要的时间间隔设置filter

#!/bin/bash

Year='$2'
Month='$2$3'
Day='$2$3$4'
Hour='$2$3$4$5'
Minute='$2$3$4$5$6'
Second='$2$3$4$5$6$7'

filter=$Second

awk -F'[ :-]' $filter'!=p{print ""}{p='$filter'}{print}' sys.log

https://github.com/tigertv/stackoverflow-answers

答案 3 :(得分:1)

这可能适合你(GNU sed):

sed 'N;/^\(.*::\).*\n\1/!P;//!s/^[^\n]*//;P;D' file

在整个文件长度上保留一个两行窗口。如果第一行键与第二行不匹配,则打印第一行,然后删除其内容。始终打印下一行,然后删除并重复。如果第一行和第二行键不匹配,则第一行现在将为空,除了换行符。

反思,答案较短:

sed 'N;P;/^\(.*::\).*\n\1/D;s/^[^\n]*//;P;D' file

始终打印双行窗口的第一行。如果第一行和第二行中的键不同,请在第二行之前创建一个空行,打印,删除并重复。

答案 4 :(得分:0)

我还有一个使用bash for循环和grep的简单解决方案。不优雅(一旦输入文件太大,我认为相当慢),但它适用于问题上的示例:

IFS=$'\n'
for i in $(cut -d ' ' -f1-3 input_file.txt | sort -u)
    do 
        grep $i input_file.txt
        echo
    done

IFS更改确保for循环将变量读取为行,而不仅仅是记录(请参阅更多here)。然后$i变量存储前3个字段的唯一值,然后grep存储在原始文件中,在每次迭代后引入一个空行echo。我现在意识到这是两次读取input_file,但无论如何,希望它有所帮助。