【问题标题】:capture text between similar start-end blocks and store result in separate files在相似的起始块之间捕获文本并将结果存储在单独的文件中
【发布时间】:2014-04-28 20:56:27
【问题描述】:

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

#Start of activity on <hostname>
....
....
....
....
#End of activity on <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

【问题讨论】:

  • 谁投了反对票,我至少可以知道原因吗??投反对票并不酷!!

标签: python perl sed awk grep


【解决方案1】:

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

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,我们将条目保存在主机名中。如果您的主机名包含&lt;&gt; 字符,请在将其分配给变量之前使用sub()gsub() 将其删除。
  • 大文件永远不会更新,除非你有支持文件内更改的gawk 4.1。我们将文件中剩余内容的输出重定向到 STDOUT,并使用 &gt; 将 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

【讨论】:

  • jaypal ..那有效..谢谢..我有一个问题..如果我的起始块是 活动的开始..我假设 $NF 将无法工作..有什么替代方案?
  • @Amistad 您的主机名是 IP 地址还是域名?你能发布一个像实际数据一样的样本吗?您需要遍历该行并找到主机名并将其分配给变量。像-/Start *of *activity *on/{f=1;for(i=1;i&lt;=NF;i++) if($i~/\&lt;/);{s=$NF};next}。只需输入类似于您的hostname 的模式即可。
  • @Amistad 检查更新的解决方案。如果您的主机名具有特定模式(仅限所有大写字母和数字),那么这应该可以正常工作。
【解决方案2】:

你可以用awk来做这样的事情:

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

所以,当我们看到#Start 时,我们将最后一个字段(即主机名)选为f,我们将使用它作为文件名。当我们看到#End 时,我们将清除文件名。在所有其他行中,如果文件名已设置(即我们在一个有用的数据块中),我们将写入命名文件f,如果没有,我们将写入重定向到名为“junk”的文件的标准输出

如果您有空格,则无需在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

【讨论】:

  • 呸!那些快速打字课程真的得到了回报 :-) 很高兴能帮上忙。
  • mark..我还有一些疑问..1> 如果我的起始块更改为 start of activity .. awk 语句会发生什么变化?
  • 我假设 2> $NF 变成了 NF
  • @Amistad 我相信 \s 匹配空白是在 gnu awk 的较新版本中引入的(可能是 4 或更高版本)。我的gnu awk 3.1.5 版不支持。
猜你喜欢
  • 1970-01-01
  • 2015-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多