【问题标题】:Using sed to get the text between two key words (but not the key words themselves)使用 sed 获取两个关键词之间的文本(但不是关键词本身)
【发布时间】:2016-02-09 01:29:51
【问题描述】:

所以我找到了这个 sed 表达式,用于获取关键字之间的文本,不包括关键字:

cat example.txt | sed '/^KEYWORD1/,/^KEYWORD2/!d; //d'

example.txt:

do
not
care
KEYWORD1
I
want
this
KEYWORD2
do
not
care

输出:

I
want
this

但是,我想确切地了解这个表达式是怎么回事。我的理解是,使用“模式范围”(如果这是不正确的术语,请纠正我),当您点击第一个匹配项时会设置一个布尔值,并且只有在该布尔值为真时才会执行模式范围之后的命令.

然后是//d,其中// 应该表示匹配的最后一个表达式/正则表达式。那么在这种有模式范围的情况下,逻辑如下是否正确:

  • 循环
  • 找到/^KEYWORD1/,将bool设置为true,继续执行!d命令,它不会删除这一行,那么由于最后一个正则表达式是/^KEYWORD1/,那么//d实际上是/^KEYWORD1/d,它会删除这一行
  • bool 为真,因此它继续不删除下 3 行,并且在所述行中未找到 /^KEYWORD1/,因此不会删除任何内容
  • 找到/^KEYWORD2/d,执行!d,然后/^KEYWORD2/d,因为这是最后一次使用的正则表达式

所以此时我不确定如何不打印之前和之后的行,因为它不执行命令(!d),除非模式范围标志设置为 true。

或者 sed 是否至少查看每一行的命令,并且由于第一个命令是反向删除,它会以某种方式改变逻辑以删除模式范围 bool 为 false 的所有其他行?

任何有关此 sed 表达式如何工作的说明将不胜感激。我已经阅读了this great resource 上下,但仍然不太了解表达式的所有细节。

【问题讨论】:

  • 如果您将光标悬停在上面的sed 标志上并选择info,您可以找到与sed 相关的大量资源。或许this链接也能启发你。

标签: bash sed


【解决方案1】:

你的误解是这样的:/address/!d 并不意味着“如果我们匹配address,就不要删除该行”; ! 是地址的否定,即“如果我们匹配address,则删除该行。”

所以单行(顺便说一句,最好不用cat

sed '/^KEYWORD1/,/^KEYWORD2/!d; //d' example.txt

这样做:

  • /^KEYWORD1/,/^KEYWORD2/!d:对于/^KEYWORD1/,/^KEYWORD2/范围之外的所有行,即,

    do
    not
    care
    do
    not
    care
    

    删除它们。 d 跳回到脚本的开头。这给我们留下了

    KEYWORD1
    I
    want
    this
    KEYWORD2
    

    我们不想打印KEYWORD1KEYWORD2

  • 对于这些行,我们一直到//d,意思是“删除最后匹配的行”。

    KEYWORD1 行上,我们通过并删除该行,因为它之前匹配过。在接下来的三行中,我们失败了,但没有匹配,所以我们不删除任何内容。在KEYWORD2 行上,我们通过并删除,因为它之前匹配过——留下两个模式之间的线。

【讨论】:

  • 谢谢!我是用 cat 编写的,因为我实际上是在将另一个命令的输出通过管道传输到文件中的 sed vs 中,但是点了。
  • 当你说'd 跳回到脚本的开头'时,你的意思是它会回到模式范围的否定被删除后剩下的内容的开头,以便第二个命令( //d) 可以遍历剩下的行吗?
  • @jshort 我的意思是这样的:sed 为每一行处理整个脚本,只有几个命令改变了标准流程。 d 是一个:当前模式空间被丢弃而不打印,下一行被加载到模式空间中,我们跳回到第一条指令。所以“跳回”实际上是针对当前周期的,而不是跳到另一条线。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
  • 2021-06-20
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 2012-10-26
相关资源
最近更新 更多