捕获类似的起始块之间的文本并将结果存储在单独的文件中

时间:2014-03-21 13:05:51

标签: python perl sed awk grep

我有一个大型文本文件,运行数百万行。在所有这些行之间,有一个数据块如下:

#Start of activity on <hostname>
....
....
....
....
#End of activity on <hostname>

在每个数据块之间,有很多我不感兴趣的垃圾数据行。上面显示的数据块随机出现在大文本文件中。我想要做的是将每个数据块移入使用块中的hostname标记将文件作为文件名分隔。 此外,在操作结束时,大文件应该只有垃圾行,并且应该没有任何块。

我目前拥有的是:

awk '/Start\sof\sactivity\son/{f=1;s="FILE"++i;next}/End\sof\sactivity\son/{f=0; close(s)}f{print > s}' bigfile

但是它不会将其分类为文件名作为主机名的文件,也不会删除选定的行。 有什么办法可以使用perl,awk,sed,grep或python来完成吗?

编辑:

对于Jaypal ..主机名现在位于开头且仅在块的起始句中。该块如下:

SGSGSINCQ14FWR52B#start of activity
........
........
........
#end of activity

2 个答案:

答案 0 :(得分:2)

试试这个(重新使用大部分现有代码):

awk '
/Start *of *activity *on/ {f=1; s=$NF; next}
/End *of *activity *on/   {f=0; close(s); next}
f{print > s; next}1
' bigfile > trunc_bigfile
  • 您将文件名设置为&#34; FILE&#34;而不是主机名。使用$NF我们将保存主机名中的条目。如果您的主机名包含<>个字符,请在将其分配给变量之前使用sub()gsub()删除它们。
  • 除非你gawk 4.1支持文件内更改,否则bigfile永远不会更新。我们将文件中剩下的whats输出重定向到STDOUT,并使用>将STDOUT重定向到trunc_bigfile
  • 我做的其他更改是,在阻止结束时,使用next以避免在已修剪的大文件中打印并使用1打印此块之外的所有其他行。

<强>更新

如果Start块具有随机顺序的主机名,那么您可以迭代该行并捕获匹配它的那一行(使用正则表达式,我使用大写字符和基于您添加到问题中的样本行的数字) 。:

/Start *of *activity *on/{f=1;for (i=1;i<=NF;i++)if($i~/[[:upper:][:digit:]]+/);{s=$i};next}
/End *of *activity *on/{f=0; close(s);next}
f{print > s;next}1
' bigfile > trunc_bigfile

答案 1 :(得分:1)

你可以使用awk

这样做
awk '/^#Start/{f=$NF;next}   /^#End/{f="";next}   {if(f){print >f}else print}' yourfile > junk

因此,当我们看到#Start时,我们将最后一个字段(即主机名)选为f,我们将其用作文件名。当我们看到#End时,我们将清除文件名。在所有其他行上,如果文件名已经设置(即我们在一个有用的数据块中),我们写入命名文件f,如果没有,我们写入stdout,重定向到一个名为“垃圾”的文件“

如果您有空格,则无需在awk

中使用空格
echo "hi with a space" | awk '/hi with/'
hi with a space

echo "hi with a space" | awk '/hi there/'

如果您的主机名从Start of activity行的末尾移动到开头,则awk将会改变如下:

echo "hostname Start of activity" | awk '/Start of activity/{print $1}'
hostname

即。主机名将是1美元,但我们仍然在某处寻找Start of activity

然后整体答案将成为:

awk '/Start of activty/{f=$1;next}   /End of activity/{f="";next}   {if(f){print >f}else print}' yourfile > junk