假设我有一个包含以下信息的文件:
...
Entry '234238': some text
some text
some text
some text
Entry '899823': some text
some text
some text
Entry '234238': more text
more text
more text
Entry '645353': some text
some text
some text
我想提取一个具体的Entry '<code>'
.例如,grep_my_block 'Entry '234238'
应该返回:
Entry '234238': some text
some text
some text
some text
Entry '234238': more text
more text
more text
注意:
- 标识块的
<code>
可能会在文件中出现多次。我们想要提取所有这样的块。 - 块可能由未知数量的行组成
我该如何使用grep
,awk
或 来做到这一点ack
?
答案1
awk "/^Entry '234238'/ {printline = 1; print; next}
/^Entry / {printline = 0}
printline"
答案2
ENTRY="'234238'"
sed -n ':s;/Entry '"$ENTRY"'/{:l;p;n;/^Entry/bs;bl;}' <<\ENTRY
Entry '234238': some text
some text
some text
some text
Entry '899823': some text
some text
some text
Entry '234238': more text
more text
more text
Entry '645353': some text
some text
some text
#END
ENTRY
输出
Entry '234238': some text
some text
some text
some text
Entry '234238': more text
more text
more text
这应该比awk
(我认为)由于sed's
流操作。
这是我做过的其中不太复杂的事情之一——一旦我全神贯注于它。这是我在不需要 GNU 扩展正则表达式的情况下成功完成的第一个任务 - 这应该是非常可移植的。
这个分支有两次——有一个锚点:s
在开始和锚点:l
为下标。它之所以有效,是因为n
运算符删除前一行sed's
模式空间当它拉入一个新的时。
一次sed
找到你的"$ENTRY"
它设置了分支:l
阿贝尔,打印该行,并拉入新的一行。然后sed
检查新行是否以短语开头'Entry'
在这种情况下,它将分支回:s
酸标签并开始再次扫描其输入以查找您指定的"$ENTRY,"
否则它只会分支到:l
阿贝尔并重复p
林特,n
分机,/check/
手术。
该命令归结为以下内容:
until end of file do
if current line contains "Entry $ENTRY" do
until next line contains 'Entry' do
print line
delete line
next line
done
done
done
答案3
您还可以使用pcregrep
:
pcregrep -M '234238.*(\n((?!Entry).)*)*' inputfile
这将生成从包含单词的行开始的所有行234238
,直到遇到包含单词 的行Entry
。
对于您的示例输入,它会生成:
Entry '234238': some text
some text
some text
some text
Entry '234238': more text
more text
more text
答案4
awk
可能是一个很好用的工具,因为问题是面向行的。
我会使用 @HaukeLaging 解决方案的这个变体,它的代码冗余较少。以 开头的每一行都会Entry
清除一个标志,但您想要的特定条目的标头会设置该标志。如果设置了该标志,则执行打印该行的默认操作。
awk "/^Entry / { printline=0; }
/^Entry '234238'/ { printline=1; }
printline"