【问题标题】:sed: match the hold space against the pattern spacesed:将保持空间与模式空间匹配
【发布时间】:2013-10-09 09:39:43
【问题描述】:

我正在寻找一个sed 命令来将保持空间的内容与模式空间相匹配。例如,假设假设的{h} 标记指的是保持空间的内容:

echo "foo: one foo three" | sed -n     \
    -e 'h; s/^\(.*\):.*$/\1/'          \
    -e 'x; s/.*: \(.*\)$/\1/'          \
    -e '/{h}/ p'

第一个-e 将整个echo 放入保持空间,然后将模式空间减少到仅初始的“foo”。第二个-e 将“foo”交换到保留空间中,并将原始echo 减少为尾随的“one foo 3”。第三个(假设的)-e 尝试将保持空间“foo”与模式空间“one foo three”进行匹配。当然没有{h}这样的标记,但如果有,模式空间会匹配,输出会是:

one foo three

sed 是否提供任何方法来做到这一点?

我的目标是在一个大文件 (4MB) 中计算所有此类匹配项。也可以使用while read 循环来完成,但它需要每行至少启动 3 个子进程,结果证明这非常慢!如果sed 不这样做,欢迎提出任何建议。

【问题讨论】:

  • 如果我理解正确:你想比较冒号前面的单词是否是冒号后面的单词之一吗?而如果匹配打印冒号后面的所有字符,如果不匹配跳行,是这样的吗?
  • 是的,就是这样。 Jotne 的回答可以解决问题。
  • 我问它是因为使用反向引用 (\1) 而不是 hold space 也很容易使用 sed 来做到这一点。
  • 怎么样?当我尝试在匹配表达式中引用前一个表达式的捕获时,我收到了Invalid back reference
  • 我添加了sed 命令作为答案。

标签: recursion sed pattern-matching


【解决方案1】:

这不是sed,而是像这样的?

echo "foo: one foo three" | awk -F": " '$2~$1 {print $2}'
one foo three

【讨论】:

    【解决方案2】:

    这是 解决方案:

    sed -ne '/^\([^:]*\):.*\1/ p' infile
    

    假设infile有内容:

    foo: one foo three
    foo: one loo three
    troo: one foo three
    three: one foo three
    

    它产生:

    foo: one foo three
    three: one foo three
    

    【讨论】:

    • 酷,这也有效。我已经接受了 Jotne 的回答,但这正是我最初想要的。
    • 如果一行是 'foo: one foobar three' sed -ne '/^([^:]*):.*\b\1\b/ p' 会更安全解决方案。尽管如此,它仍然需要一个分隔符 char ':' 并且不匹配 hold 与模式。
    【解决方案3】:

    正如已经展示的那样,这个特定任务的“正确”(最简单)方法是在完全不使用保持空间的情况下进行匹配。

    但是,为了一个有趣的练习,如果您真的不得不使用保持空间(也许作为更复杂的 sed 程序的一部分)怎么办?

    假设保留空间不包含任何\n(如上面原始问题中的情况),以下将起作用:

    -e 'H;g;s/^\([^\n]*\)\n\(.*\1.*\)/\2/p'
    

    这会将模式空间附加到保持空间(由\n分隔),然后将其复制回模式空间,并将第一行(即原始保持空间)与其余行(即原始模式)匹配空间)。如果发生匹配,则通过丢弃其第一行来恢复原始模式空间,然后打印结果。

    (请注意,没有要求匹配出现在单词边界内 - 甚至保持空间是否只有一个单词。例如,保持空间中的 foo bar 将匹配模式空间中的 loofoo barzoo . 如果这不是可取的,在上面的\1 之前和之后添加\b 应该可以解决问题。)

    为了增加乐趣,我们还要求在同一个 sed 程序中为将来的匹配保留原始保持空间。为了做到这一点,在上面的代码之后,我们将修改后的保持空间再次复制到模式空间,然后丢弃除第一行以外的所有内容(即原始保持空间),然后将其放回保持空间:

    -e 'g;s/\n.*//;h'
    

    将原始问题放在一起,完整的 sed 命令将是:

    echo "foo: one foo three" | sed -n            \
        -e 'h; s/^\(.*\):.*$/\1/'                 \
        -e 'x; s/.*: \(.*\)$/\1/'                 \
        -e 'H; g; s/^\([^\n]*\)\n\(.*\1.*\)/\2/p' \
        -e 'g; s/\n.*//; h'
    

    (你可以看到为什么,严格地在原始问题的范围内,这不是最好的方法。同样在原始问题的范围内,最后一个 -e 没有做任何有用的事情并且可以省略。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 2018-11-21
      • 1970-01-01
      • 1970-01-01
      • 2013-07-31
      相关资源
      最近更新 更多