【问题标题】:Sed delete everything between 2 patterns, but not including the patternssed 删除 2 个模式之间的所有内容,但不包括模式
【发布时间】:2018-05-12 21:15:00
【问题描述】:

我在这方面找到了一些示例,但没有一个完全符合我的要求。

我想删除 1 和其他几种可能的模式之间的所有内容,但不包括模式本身。模式对仅是每行,而不是多行。

例如

:1543453 Brown Fox
:789 123456 Cat
:abcdef Yellow Duck

:Brown Fox
:Cat
:Yellow Duck

所以第一个匹配的模式是“:”,第二个是“棕色”或“猫”或“黄色”

【问题讨论】:

    标签: bash sed bsd


    【解决方案1】:

    有蛮力和无知,有时效果很好:

    sed -e 's/^:.* Brown/:Brown/' \
        -e 's/^:.* Cat/:Cat/' \
        -e 's/^:.* Yellow/:Yellow/' \
        data-file.txt
    

    您可以通过-E(BSD、Mac、Linux)或-r(仅限Linux)选项使用“扩展正则表达式”:

    sed -E 's/^:.* (Brown|Cat|Yellow)/:\1/' data-file.txt
    

    两者都在样本数据上产生所需的输出。

    请注意,使用的.* 是“贪婪”的。给定输入文件:

    :1543453 Brown Fox
    :789 123456 Cat
    :abcdef Yellow Duck
    :quantum mechanics eat Yellow Ducks for being yellow (but leave Yellow Dafodils alone)
    

    两个脚本都产生:

    :Brown Fox
    :Cat
    :Yellow Duck
    :Yellow Dafodils alone)
    

    您需要 Perl 或使用 PCRE(Perl 兼容的正则表达式)或其他一些程序增强的 sed,以避免贪婪。例如:

    $ perl -n -e 'print if s/^:.*? (Brown|Cat|Yellow)/:\1/' data-file.txt
    :Brown Fox
    :Cat
    :Yellow Duck
    :Yellow Ducks for being yellow (but leave Yellow Dafodils alone)
    $
    

    【讨论】:

    • 我不确定模式是否已修复。也许使用pat1=":";pat2="(Cat|Yellow|Brown)";sed -r "s/(${pat1}).*(${pat2})/\1\2/" inputfile
    • @WalterA:从长远来看,有无数类似的可能性。我处理了提出的问题,因为试图猜测哪些替代方案是相关的,这太麻烦了。将正则表达式作为参数正确引用是很棘手的,但要小心。 (是的,在替换模式中重复 : 不一定是最好的技术;使用捕获并在替换中引用它更通用。
    • 你可以用sed -E 's/(Brown|Cat|Yellow)/\x01\1/; s/^:.*\x01/:/' data-file.txt来避免贪婪(当pattern2在pattern1之后)。
    • 感谢您的回复。我正在努力让它发挥作用。不确定是不是因为我在 bash 脚本中使用 BSD。我是新手,正在学习。
    • 好的。我使用 Mac (BSD) sed 在运行 macOS 10.13.4 的 Mac 上测试了我展示的片段。
    最近更新 更多