【问题标题】:grep invert search with contextgrep 使用上下文反转搜索
【发布时间】:2011-04-21 21:46:19
【问题描述】:

我想过滤掉文件中匹配行前后的几行。

这将删除我不想要的行:

$ grep -v "line that i don't want"

这将打印我不想要的行之前和之后的 2 行:

$ grep -C 2 "line that i don't want"

但是当我将它们组合起来时,它不会过滤掉我不想要的行之前和之后的 2 行:

# does not remove 2 lines before and after the line I don't want:
$ grep -v -C 2 "line that i don't want"   

如何过滤掉我不想要的行,以及它之前和之后的行?我猜sed 会更好...

编辑:我知道这可以在几行 awk/Perl/Python/Ruby/etc 中完成,但我想知道是否有一个简洁的单行代码可以从命令行运行。

【问题讨论】:

    标签: unix shell sed grep


    【解决方案1】:

    2019 年解决方案

    这是一个简单的解决方案,在其他地方可以找到:

    grep --invert-match "test*"
    

    选择所有不匹配“test*”。超级好用又好记!

    (编辑)

    这并没有完全回答原始问题并返回整组不匹配的行。

    【讨论】:

    • 此解决方案不会删除模式匹配行的下一个和之后。
    【解决方案2】:

    实际上,我用两个连续的 grep 解决了它。这对我来说似乎更直接。

    grep -C "match" yourfile | grep -v -f - yourfile
    

    【讨论】:

    • 这个解决方案并不总是有效;详情请见another answer
    【解决方案3】:

    我认为@fxm27 的回答非常好。

    我要补充的是,如果您事先知道后续行的模式,您可以使用 egrep 以另一种方式解决此问题。

    command | egrep -v "words|from|lines|you|dont|want"
    

    这将执行“包含 OR”,这意味着将排除匹配 any 的行。

    【讨论】:

      【解决方案4】:

      如果这些行都是唯一的,您可以将要删除的行 grep 到一个文件中,然后使用该文件从原始文件中删除这些行,例如

      grep -C 2 "line I don't want" < A.txt > B.txt
      grep -f B.txt A.txt
      

      【讨论】:

      • 可以在没有边文件的情况下单行:grep -C1 unwanted A.txt | grep -vFf- A.txt ...这使用从标准输入读取“文件”的-f-。另外,我建议-F 用于固定字符串。
      • 最后,OP不见了-v
      【解决方案5】:

      试试这个:

      sed 'h;:b;$b;N;N;/PATTERN/{N;d};$b;P;D' inputfile
      

      您可以改变模式前N 命令的数量以影响要删除的行数。

      您可以通过编程方式构建一个包含N 命令数量的字符串:

      C=2 # corresponds to grep -C
      N=N
      for ((i = 0; i < C - 1; i++)); do N=$N";N"; done
      sed "h;:b;\$b;$N;/PATTERN/{N;d};\$b;P;D" inputfile
      

      【讨论】:

      • 不,你的意思是grep 就是不能这样做?!有原因吗?这对我来说是违反直觉的
      • @naxa:当-C-v 一起使用时,-C 包括排除行而不是排除附加行。试试这个:printf '%s\n' {1..36} | grep --color -C 2 -v '^2.',你会看到 20、21、28 和 29 被包括在内,而不是 18、19、30 和 31 被排除在外。顺便说一下,POSIX 没有指定-C 选项。
      • 啊,我明白了。非常感谢您的关注和现在彩色的好例子!我尝试过使用-A 和-B,但它们的工作方式与-C 相同。既然我知道我想找什么,它们似乎也“非 posix”了。
      • 即使在手册页的帮助下,我也很难理解您的单行 sed 逐个命令执行的操作。我可能会稍后回顾,但如果不是太麻烦,你介意把它分解吗?我认为这将有利于答案的质量。
      【解决方案6】:
      awk 'BEGIN{n=2}{a[++i]=$0}
      /dont/{
        for(j=1;j<=i-(n+1);j++)print a[j];
        for(o=1;o<=n;o++)getline;
        delete a}
      END{for(i in a)print a[i]} ' file
      

      【讨论】:

      • 我知道您可能已经知道这一点,因为您的 XP 比我多得多,但是您可能希望添加更多解释,而不仅仅是代码段,以解决 OP 询问的事实对于 grep 解决方案,同时提供其他非常有效且非常有用的 AWK 解决方案。谢谢!
      • @DermotCanniffe,大声笑接受的答案使用 sed 更加复杂。
      • 非常正确。尽管我很喜欢 sed,但我认为 awk 程序更容易解释。 :)
      猜你喜欢
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 2012-09-12
      • 1970-01-01
      • 2019-08-25
      • 2022-01-13
      • 2020-12-08
      • 1970-01-01
      相关资源
      最近更新 更多