如何从大文件中提取包含指定字符串的key起始文本块?
提取包含指定字符串的key块
需求说明
我有一个大文件,结构是以key = ...开头的块——每个块从一行key开头的行开始,到下一行key开头的行结束(最后一个块到文件末尾)。现在需要提取所有包含字符串text的块。
示例文件内容
key = asbh some lines of **text** key = kafeia some more **text** and additionally more **text** and more key = lklfh this is another block
注:key行绝不会包含目标字符串text。
期望输出
key = asbh some lines of **text** key = kafeia some more **text** and additionally more **text** and more
尝试过的方法及问题
less myfile.txt | sed -n '/key/,/text/p' | less:这个命令会从第一个key开始输出,直到遇到text就停止,会返回大量无关内容,不符合需求。less myfile.txt | grep -Pzl '(?s)^key([^key]|\n)*text' | less:这个正则只匹配key到text之间的内容,不会包含到下一个key之前的所有内容,无法完整获取整个块。- 尝试学习Unix中的if语句用法,但作为新手仍有困惑,希望得到清晰的解决方案。
解决方案
方法1:使用awk实现(推荐,高效处理大文件)
可以把以下内容保存为脚本文件(比如extract_blocks.awk):
/^key/ { if (block && index(block, "text") != 0) { print block } block = $0 "\n" next } { block = block $0 "\n" } END { if (index(block, "text") != 0) { print block } }
使用方式:
awk -f extract_blocks.awk myfile.txt
也可以直接写成一行命令:
awk '/^key/{if(block&&index(block,"text"))print block;block=$0"\n";next}{block=block$0"\n"}END{if(index(block,"text"))print block}' myfile.txt
原理:
- 匹配到
key开头的行时,先检查之前缓存的block是否包含text,如果是就打印该块;然后重置block为当前行。 - 非
key开头的行,追加到当前block中。 - 文件结束时,检查最后一个
block是否包含text,如果是就打印。
方法2:使用sed实现
sed -n ' /^key/{ :start N /\nkey/!b start /text/p d } $ {/text/p} ' myfile.txt
原理:
- 匹配到
key开头的行后,不断追加下一行(N命令),直到遇到下一行key为止。 - 检查当前收集的内容是否包含
text,如果是就打印。 - 最后处理文件末尾的块,检查是否包含
text并打印。
Unix if语句基础解释
在shell脚本中,if语句用于条件判断,基础格式:
if [ 条件 ]; then # 条件成立时执行的命令 elif [ 其他条件 ]; then # 其他条件成立时执行的命令 else # 所有条件都不成立时执行的命令 fi
比如判断文件是否存在:
if [ -f myfile.txt ]; then echo "文件存在" else echo "文件不存在" fi
在awk这类工具中,if语句语法更接近常规编程语言:
if (条件) { # 执行代码 } else { # 执行其他代码 }
就像上面awk方案中用到的,用来判断块中是否包含目标字符串。
内容的提问来源于stack exchange,提问作者Magi
相关产品推荐
相关产品推荐

