合并重复前缀

合并重复前缀

我有一个日志文件,例如:

Bug123:c:SomeComment
Bug222:c:SomeOtherComment
Bug123:c:SecondComment

我需要制作:

Bug123
    SomeComment
    SecondComment
Bug222
    SomeComment

使用 bash,我似乎想不出一种简单的方法来完成此任务。有任何想法吗?

答案1

$ awk 'BEGIN {FS=":"} {comments[$1][NR]=$3} END {for (bug in comments) { print bug; for (comment in comments[bug]) { print "    ",comments[bug][comment] } } }  ' /path/to/input
Bug123
     SomeComment
     SecondComment
Bug222
     SomeOtherComment

这是通过在读取输入文件时设置一个多维数组,然后按照看到“错误”的顺序遍历结果数据来实现的。通过一些小的调整,可以修改它以对外层数组进行排序。

答案2

这是一种有趣的方法vi(或者,实际上,ex如果您省略每个命令的前导冒号):

:%!awk -F: '{a[$1];print} END {for (i in a) {print i}}'
:v/:/m0
:%!sort -st: -k1,1
:%s/^.*:/\t/

解释:

Awk 命令按原样打印每一行,并在文件末尾转储所有唯一第一个字段的列表。

v命令m将所有行移至第 0 行(文件的开头)有任何冒号。 (换句话说,是从 输出的第一个字段的列表awk。)

sort命令对s表进行排序,保留行的顺序,而不是根据第一个字段排列它们。 (我们已经将“标题”字段移至文件的开头。)

然后substitute 命令将每个非标题行的前缀变成制表符。


您提供的输入的结果:

Bug123
    SomeComment
    SecondComment
Bug222
    SomeOtherComment

附加说明:

:(冒号)是您键入vi以开始ex-style 命令的内容。

%是一个地址范围ex。它的意思是“将以下操作/命令应用于缓冲区(文件)中的所有行。”

当与地址一起使用时,!开始“过滤器” ex:地址指定的行作为输入馈送到指定的外部命令,并在缓冲区中被该命令的输出替换。

-F:设置 Awk 字段分隔符。

{}(花括号)在 Awk 中用于包围要运行的命令。既然没有awk花括号前面的地址(单引号内),花括号中的操作将应用于每一行输入。

a[$1]使用当前行的第一个字段 ( $1) 作为索引创建一个数组元素。因为它没有说= "whatever",所以数组元素没有价值,但这并不重要;我们只希望数组包含该元素。

;终止该 Awk 命令。

print是打印当前行(默认情况下)或传递的任何参数(如后面所示print i)的 Awk 命令。

END标记在处理所有输入(到 Awk)后要执行的操作块(在大括号中)。

for循环打印名为 的数组的所有索引a。这是日志文件中删除重复的第一个字段,没有特定的顺序。

关于 Awk 命令就讲这么多。

v命令是与全局命令ex相反的命令gg执行一个动作所有行匹配某种模式。 v对不匹配给定模式的所有行执行指定的操作。

/开始和结束模式。就:在这种情况下。

m意思是“移动”。因此,:v/:/m0vi所有不包含任何冒号的行移动到文件顶部。

其余的命令应该很清楚。 :)

答案3

Perl 一行

perl -MList::Util=uniq -F: -lane '
        push @keys, $F[0];
        push @{ $comment{$F[0]} }, $F[2];
    } END { 
        for $key (uniq @keys) {
            print $key;
            print "    $_" for @{$comment{$key}};
        }
' file

相关内容