【问题标题】:Sed to extract text between two stringsSed 提取两个字符串之间的文本
【发布时间】:2013-05-14 15:26:17
【问题描述】:

请帮助我使用 sed。 我有一个像下面这样的文件。

START=A
  xxxxx
  xxxxx
END
START=A
  xxxxx
  xxxxx
END
START=A
  xxxxx
  xxxxx
END
START=B
  xxxxx
  xxxxx
END
START=A
  xxxxx
  xxxxx
END
START=C
  xxxxx
  xxxxx
END
START=A
  xxxxx
  xxxxx
END
START=D
  xxxxx
  xxxxx
END

我想获取 START=A, END 之间的文本。 我使用了以下查询。

sed '/^START=A/, / ^END/!d' input_file

这里的问题是, 我得到了

START=A
  xxxxx
  xxxxx
END
START=D
  xxxxx
  xxxxx
END

而不是

START=A
  xxxxx
  xxxxx
END

Sed 贪婪地寻找。

请帮我解决这个问题。

提前致谢。

我可以使用 AWK 来实现上述目标吗?

【问题讨论】:

标签: regex shell sed awk


【解决方案1】:
sed -n '/^START=A$/,/^END$/p' data

-n 选项表示默认不打印;然后脚本说'在包含START=A 的行和下一个END 之间打印。

您也可以使用awk

一个模式可以由两个用逗号分隔的模式组成;在这种情况下,执行的操作是 从第一个模式出现到第二个模式出现的所有行。

(来自 Mac OS X 上的 man awk)。

awk '/^START=A$/,/^END$/ { print }' data

给定问题中数据文件的修改形式:

START=A
  xxx01
  xxx02
END
START=A
  xxx03
  xxx04
END
START=A
  xxx05
  xxx06
END
START=B
  xxx07
  xxx08
END
START=A
  xxx09
  xxx10
END
START=C
  xxx11
  xxx12
END
START=A
  xxx13
  xxx14
END
START=D
  xxx15
  xxx16
END

使用 GNU sed 或 Mac OS X (BSD) sed 和使用 GNU awk 或 BSD awk 的输出是相同的:

START=A
  xxx01
  xxx02
END
START=A
  xxx03
  xxx04
END
START=A
  xxx05
  xxx06
END
START=A
  xxx09
  xxx10
END
START=A
  xxx13
  xxx14
END

请注意我是如何修改数据文件的,以便更容易查看打印的各种数据块在文件中的来源。

如果您有不同的输出要求(例如“仅在 START=A 和 END 之间的第一个块”,或“仅最后一个 ...”),那么您需要在问题中更清楚地表达出来。

【讨论】:

  • 感谢您的回复。我需要 START=A 和下一个 END 之间的文本,上面给出了 START=A 和最后一个 END 之间的数据。希望你能得到我的答案。
  • 不,它没有。 awksed 脚本 - 至少在我的机器上使用我提供的数据文件副本 - 打印 START=AEND 之间的 5 个数据块,以及 START=B 到 @ 的块987654339@、START=CENDSTART=DEND 都从输出中省略。你在哪个平台上测试?您使用的是哪个版本的sed?您使用的是哪个版本的awk? (我注意到您的测试数据逐字重复START=AEND 之间的块。如果您之间有不同的行会更好,这样您就可以看到正在打印哪些行。)
  • 当我测试这个时,开始和结束 toeks 包含在输出中,而我的印象是 OP 只需要它们之间的数据。
  • @LennartRolland:示例所需的输出具体包括 START=AEND 行。如果您不希望出现开始和结束标记,可以像这样使用sedsed -n -e '/^START=A$/,/^END$/ { /^START=A$/d; /^END$/d; p; }'。或者,您可以像这样使用awkawk '/^START=A$/,/^END$/ { if ($0 != "START=A" && $0 != "END") print }'(基本思想相同,但如果需要,您可以以多种不同方式对条件进行编码)
【解决方案2】:

基本版 ...

sed -n '/START=A/,/END/p' yourfile

更强大的版本...

sed -n '/^ *START=A *$/,/^ *END *$/p' yourfile

【讨论】:

  • 你能解释一下,在sed模式字符串中的含义吗?
  • @Vikrant - , 分隔由两个正则表达式定义的 范围 的两个部分,以便返回第一个模式和第二个模式之间的行。
【解决方案3】:

您的sed 表达式在结束前有一个空格,即/ ^END/。所以sed 得到了起始模式,但没有得到结束模式并继续打印直到结束。使用sed '/^START=A/, /^END/!d' input_file(注意/^END/

【讨论】:

  • 关于sed 正则表达式中的空格的好点,虽然它使引用的输出更加令人费解(如'我不能用原始脚本重现引用的输出,但删除无关的空间和它工作正常,虽然 cackhanded')。您至少可以将awk 脚​​本的最后一部分简化为/END/{flag=0},这可能会在标志已经为零时将其设置为零,但这并没有什么坏处。你也可以使用/START=A/,/END/{print},这样更简单。
  • 是的,/START=A/,/END/{print} 这要简单得多,但它已经在您的答案中显示出来了 :) 我只是在玩一个标志 :)。实际上,在您给出awk 的解决方案之后,他不需要做任何其他事情。我将删除我的awk 解决方案。这可能会导致更多的混乱而不是做任何好事:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-03
  • 2021-07-23
  • 2016-08-13
  • 1970-01-01
  • 2015-11-10
  • 2012-11-03
相关资源
最近更新 更多