我有一个大型文本文件,运行数百万行。在所有这些行之间,有一个数据块如下:
#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
答案 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
$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