【问题标题】:Deleting n lines in both directions and the match in sed?删除两个方向的n行和sed中的匹配?
【发布时间】:2015-05-28 23:52:45
【问题描述】:

在它起作用之前删除匹配和两行:

sed -i.bak -e '/match/,-2d' someCommonName.txt

在匹配成功后删除两行:

sed -i.bak -e '/match/,+2d' someCommonName.txt

但是删除匹配,它之后的两行和它之前的两行不起作用?

sed -i.bak -e '/match/-2,+2d' someCommonName.txt
sed: -e expression #1 unknown command: `-'

这是为什么呢?

【问题讨论】:

  • 那个../somedir/*/someCommonName.txt太危险了?
  • 第一个对我不起作用:seq 10 | sed -e '/5/,-2d',例如,返回“sed: -e expression #1, char 5: unexpected `,'”错误。事实上,我怀疑第一个命令对你有用。见Delete range of lines above pattern with sed (or awk)
  • 不危险,只是更难读懂,去重点
  • 您提出了一个问题,1 小时后选择了一个不包含有效解决方案的答案。只是一个想法-也许如果您将问题留待更长时间,您就会得到一个可行的解决方案。 FWIW 接受的答案中建议的方法不适用于彼此相距 2 行的 2 条匹配线的边缘情况。
  • 现在可能为时已晚,因为每个人都会看最近的帖子。你可以给它一天左右的时间看看,但你会知道你的下一个问题。您还应该发布一些具体的、可测试的、示例输入和预期输出,其中包括要处理的硬/非显而易见的案例,例如如果您在示例输入文件中有 match 仅由 1 行分隔 - 预期的输出是什么?

标签: regex bash sed


【解决方案1】:

sed 对一系列地址进行操作。这意味着一个或两个表达式,而不是三个。

/match/ 是一个匹配正则表达式的地址。

-2 是一个地址,它在前面指定了两行

+2 是一个地址,它在后面指定两行

因此:

/match/,-2 是一个范围,它指定匹配match 的行到前两行。

另一方面,/match/-2,+2d 包含三个地址,因此没有意义。

要删除模式前后的两行,我会推荐这样的内容 (modified from this answer):

sed -n "1N;2N;/\npattern$/{N;N;d};P;N;D"

这会在缓冲区中保留 3 行并读取文件。当模式在最后一行中找到时,它会再读取两行并删除所有 5 行。请注意,如果模式在文件的前两行中,这将不起作用,但它是一个开始。

【讨论】:

    【解决方案2】:
    sed -i .bak '/match/,-2 {/match/!d;};/match/,+2d' YourFile
    

    试试这个(不能在这里测试,-2 在我的 sed 版本中不可用)

    【讨论】:

    • @nerronLeVelu 知道您需要什么版本吗?我正在运行 Ubuntu 14.04 LTS,它只是附带...但如果我需要获得一个单独的包或重新编译它或其他什么,我会为此而努力。
    • 什么是!d?我得到`sed: -e expression #1, char 8: unexpected ,' with gnu sed, Ubuntu 20_04
    • 减号不起作用,see
    【解决方案3】:

    我没有完整的解决方案,只有一个大纲:sed 是一个非常简单的工具,它不会同时做两件事。我的方法是运行sed 一次删除模式后的两行但保留模式本身。然后可以将结果再次通过管道传送到sed 以删除模式和之前的两行。

    【讨论】:

      【解决方案4】:

      FWIW 这就是我真正的工作方式(只需更改 ba 值以在找到 match 之前/之后删除不同数量的行):

      $ cat file
      1
      2
      3
      4
      5 match
      6
      7
      8
      9
      
      $ awk -v b=2 -v a=2 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file file
      1
      2
      8
      9
      
      $ awk -v b=3 -v a=1 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file file
      1
      7
      8
      9
      

      请注意,以上假设当删除窗口中出现 2 个“匹配”时,您希望将删除基于原始匹配项,而不是在找到第一个匹配项后会发生什么导致第二个匹配项被删除:

      $ cat file2
      1
      2
      3
      4 match
      5
      6 match
      7
      8
      9
      
      $ awk -v b=2 -v a=2 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file2 file2
      1
      9
      

      与输出相反:

      1
      7
      8
      9
      

      因为删除第一个 match 之后的 2 行将删除第二个 match,因此不会删除 THAT 之后的 2 行,因为它们不再位于 match 之后的 2 行内。

      需要考虑的其他事项:

      $ diff --changed-group-format='%<' --unchanged-group-format='' file <(grep -A2 -B2 match file)
      1
      2
      8
      9
      
      $ diff --changed-group-format='%<' --unchanged-group-format='' file2 <(grep -A2 -B2 match file2)
      1
      9
      

      这使用 bash 和 GNU diff 3.2,如果/其他 shell/diff 将支持这些构造/选项,请确定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多