如何 grep 块?或者我应该使用 awk/ack ?

如何 grep 块?或者我应该使用 awk/ack ?

假设我有一个包含以下信息的文件:

...
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

注意:

  1. 标识块的<code>可能会在文件中出现多次。我们想要提取所有这样的块。
  2. 块可能由未知数量的行组成

我该如何使用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"

相关内容