【问题标题】:grep redirect non-matchinggrep 重定向不匹配
【发布时间】:2011-06-15 23:52:29
【问题描述】:

我正在为以一些模式开头的行做一个简单的 grep,例如:

grep -E "^AAA" myfile > newfile

我还想(同时)将那些不匹配的行重定向到另一个文件。
我知道可以简单地执行两次并在第二次尝试中使用 -v ,但是文件(相对)很大并且只读取一次会节省一些非常宝贵的时间...

我正在考虑将不匹配重定向到 stderr,例如:

grep -E -magic_switch "^AAA" myfile > newfile 2> newfile.nonmatch

grep 是否可以实现这个技巧,还是我应该只编写代码?

(可能有额外的价值 - 我在 bash 脚本中对此进行编码)

【问题讨论】:

    标签: bash file command-line grep


    【解决方案1】:

    我担心这可能是不可能的。我会使用 Perl 并执行以下操作:

    if (/^AAA/) {
       print STDOUT $_;
    }
    else
    {
       print STDERR $_;
    }
    

    【讨论】:

      【解决方案2】:

      我不相信这可以用grep 完成,但它只是几行Perl:

      #! /usr/bin/perl
      # usage: script regexp match_file nomatch_file < input
      
      my $regexp = shift;
      open(MATCH, ">".shift);
      open(NOMATCH, ">".shift);
      
      while(<STDIN>) {
          if (/$regexp/o) {
              print MATCH $_;
          } else {
              print NOMATCH $_;
          }
      }
      

      或 Python,如果您愿意:

      #! /usr/bin/python
      # usage: script regexp match_file nomatch_file < input
      
      import sys
      import re
      
      exp = re.compile(sys.argv[1])
      match = open(sys.argv[2], "w")
      nomatch = open(sys.argv[3], "w")
      
      for line in sys.stdin:
          if exp.match(line): match.write(line)
          else:               nomatch.write(line)
      

      (两者都完全未经测试。您的里程可能会有所不同。在禁止的地方无效。)

      【讨论】:

      • 非常高兴,非常感谢!我只需要 py 代码...您刚刚通过参考为我节省了 5 分钟的浏览时间;)
      【解决方案3】:

      这将起作用:

      awk '/pattern/ {print; next} {print > "/dev/stderr"}' inputfile
      

      awk -v matchfile=/path/to/file1 -v nomatchfile=/path/to/file2 '/pattern/ {print > matchfile; next} {print > nomatchfile}' inputfile
      

      #!/usr/bin/awk -f
      BEGIN {
          pattern     = ARGV[1]
          matchfile   = ARGV[2]
          nomatchfile = ARGV[3]
          for (i=1; i<=3; i++) delete ARGV[i]
      }
      
      $0 ~ pattern {
          print > matchfile
          next
      }
      
      {
          print > nomatchfile
      }
      

      这样调用最后一个:

      ./script.awk regex outputfile1 outputfile2 inputfile
      

      【讨论】:

      • 不错!我总是更喜欢使用标准工具来编写代码,单行代码值得加分;)
      【解决方案4】:

      这是一个适合你的功能:

      function perg {
        awk '{y = $0~z ? "out" : "err"; print > "/dev/std" y}' z="$1" "$2"
      }
      

      与文件一起使用

      perg ^AAA myfile > newfile 2> newfile.nonmatch
      

      或来自管道

      cat myfile | perg ^AAA > newfile 2> newfile.nonmatch
      

      【讨论】:

        【解决方案5】:

        您可以在读取文件时使用进程替换来复制管道(灵感https://unix.stackexchange.com/a/71511)。这应该几乎一样高效,因为该文件仍然只被读取一次。

        这样的事情应该可以工作:

        cat file.txt | tee >(grep 'pattern' > matches.txt) | grep -v 'pattern' > non-matches.txt

        【讨论】:

          猜你喜欢
          • 2017-01-23
          • 2020-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-03
          相关资源
          最近更新 更多