如何从与模式匹配的日志文件中查找数字

如何从与模式匹配的日志文件中查找数字

我想从日志文件中提取一些信息,其中包含:

...
Running ep. 0
...
...
Initial position for this ep is 7.338690864048985,28.51815509409351,11.795143979909135
...
...
...
Running ep. 1
...
...
Initial position for this ep is 10.599326804010953,7.514871863851674,14.843070346933654
...
...

现在我有一个 bash 代码,可以从中提取一些数据:

cat screen2.dat|grep -oP 'Running ep. \K([0-9]+)|(?<=for this ep is )[+-]?[0-9]+([.][0-9]+)?'|paste -d' ' - -

但输出只是“Running ep”之后的数字。以及“此 ep 的初始位置是”之后的第一个数字

0 7.338690864048985 
1 10.599326804010953 
.
.
.

我期待类似的事情

0 7.338690864048985 28.51815509409351 11.795143979909135
1 10.599326804010953 7.514871863851674 14.843070346933654
.
.
.

答案1

我认为您过度指定了表达式。您只匹配 substring 之后的单个浮点数for this ep is。如果你想要该行的其余部分,请使用类似的东西

grep -oP 'Running ep\. \K(.*)|for this ep is \K(.*)' screen2.dat |
paste -d ' ' - -

使用标准sed,你可以写

sed -n -e 's/^Running ep\. //p' -e 's/.*for this ep is //p' screen2.dat |
paste -d ' ' - -

只需砍掉(用什么都没有替代来删除)行中不需要的部分即可。

您也可以awk以同样的方式使用,

awk '/^Running ep\. / || /for this ep is / { print $NF }' screen2.dat |
paste -d ' ' - -

或者,一次性格式化所有内容,

awk '/^Running ep\. / { ep = $NF } /for this ep is / { print ep, $NF }' screen2.dat

答案2

您的代码[+-]?[0-9]+([.][0-9]+)?与点后带有可选数字的单个数字相匹配。如果您想要其中三个,请这样说:([+-]?[0-9]+([.][0-9]+)?,?){3}

但你真正想要的,只需一个sed脚本即可获得:

sed -e '/Running ep. /{s///;h;}' -e '/.*for this ep is /!d;s///;H;x;s/[\n,]/ /g' screen2.dat
  • /Running ep. /{...}{}是只对匹配的行执行里面的所有内容Running ep.
  • 对于这些行,s///删除之前匹配的部分并将该行移动到h旧空间
  • /.*for this ep is /!d否 所有与 ( !) 不匹配其他模式的行都可以被d选择,
  • 对于其余部分,s///只需再次删除模式,将行的其余部分保留为所有数字
  • H将此剩余附加到保留空间,我们可以在其中获取 ep 编号
  • x交换缓冲区,因此我们在保留空间中收集的两个部分现在都在模式空间中,并且
  • s/[\n,]/ /g用空格替换嵌入的换行符和所有逗号

答案3

withpcregrep及其Multiline 模式:

$ <input pcregrep -M -o{1..4} --om-separator=' ' \
  '(?sm)^Running ep\. (\d+)$.*?^Initial position for this ep is ([+-]?\d+(?:\.\d+)?),((?2)),((?2))$'
0 7.338690864048985 28.51815509409351 11.795143979909135
1 10.599326804010953 7.514871863851674 14.843070346933654

但请注意,如果Initial...特定的 缺少Running ep...,则.*?会很高兴地与另一个匹配Running ep...,并且您最终会在给定的一组值前面得到错误的 ep 编号。

可能更好地用gawk类似的东西来做到这一点:

<input gawk -v 'FPAT=[+-]?[0-9]+([.][0-9]+)?' '
  /^Running ep/ && NF == 1 {ep = $1; next}
  /^Initial position for this ep is/ && ep != "" && NF == 3 {
    print ep, $1, $2, $3
    ep = "" # omit if there can be more than one "Initial position"
            # per ep.
  }'

其中FPAT将字段定义为与正则表达式(数字)匹配的字符串,我们只打印一行输出初始位置行,如果有相应的跑步EP线以前见过。

答案4

在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ awk '/Running ep/{ep=$NF} /Initial position/{print ep, $NF}' file
0 7.338690864048985,28.51815509409351,11.795143979909135
1 10.599326804010953,7.514871863851674,14.843070346933654

如果您确实想用空格替换这些逗号,那么:

$ awk '/Running ep/{ep=$NF} /Initial position/{gsub(/,/," ",$NF); print ep, $NF}' file
0 7.338690864048985 28.51815509409351 11.795143979909135
1 10.599326804010953 7.514871863851674 14.843070346933654

相关内容