【问题标题】:grep lines before and after in aix/ksh shellaix/ksh shell 之前和之后的 grep 行
【发布时间】:2013-10-01 10:04:50
【问题描述】:

我想提取匹配模式前后的行。

eg: 如果文件内容如下

absbasdakjkglksagjgj
sajlkgsgjlskjlasj
hello
lkgjkdsfjlkjsgklks
klgdsgklsdgkldskgdsg

我需要 find hello 并在 'hello' 前后显示行

输出应该是

sajlkgsgjlskjlasj
hello
lkgjkdsfjlkjsgklks

这对于 GNU 是可能的,但我需要一种在没有安装 GNU 的 AIX / KSH SHELL 中工作的方法。

【问题讨论】:

  • 您不能使用-A-B-C 选项吗?
  • 它在 AIX SHELL 上不起作用。未安装 GNU。 (KSH 壳)

标签: linux shell unix ksh aix


【解决方案1】:
sed -n '/hello/{x;G;N;p;};h' filename

【讨论】:

    【解决方案2】:

    我发现一次构建 GNU coreutils 并受益于更多功能http://www.gnu.org/software/coreutils/

    【讨论】:

      【解决方案3】:

      由于您的机器上将安装 Perl,您可以使用以下代码,但您最好安装 GNU 实用程序。这有选项 -b n1 用于匹配之前的行,-f n1 用于匹配之后的行。它适用于 PCRE 匹配(因此,如果您想要不区分大小写的匹配,请在正则表达式之后添加 i,而不是使用 -i 选项。我还没有实现 -v-l;我不需要那些.

      #!/usr/bin/env perl
      #
      # @(#)$Id: sgrep.pl,v 1.7 2013/01/28 02:07:18 jleffler Exp $
      #
      # Perl-based SGREP (special grep) command
      # 
      # Print lines around the line that matches (by default, 3 before and 3 after).
      # By default, include file names if more than one file to search.
      #
      # Options:
      # -b n1     Print n1 lines before match
      # -f n2     Print n2 lines following match
      # -n        Print line numbers
      # -h        Do not print file names
      # -H        Do     print file names
      
      use warnings;
      use strict;
      use constant debug => 0;
      use Getopt::Std;
      my(%opts);
      
      sub usage
      {
          print STDERR "Usage: $0 [-hnH] [-b n1] [-f n2] pattern [file ...]\n";
          exit 1;
      }
      
      usage unless getopts('hnf:b:H', \%opts);
      usage unless @ARGV >= 1;
      
      if ($opts{h} && $opts{H})
      {
          print STDERR "$0: mutually exclusive options -h and -H specified\n";
          exit 1;
      }
      
      my $op = shift;
      
      print "# regex = $op\n" if debug;
      
      # print file names if -h omitted and more than one argument
      $opts{F} = (defined $opts{H} || (!defined $opts{h} and scalar @ARGV > 1)) ? 1 : 0;
      $opts{n} = 0 unless defined $opts{n};
      
      my $before = (defined $opts{b}) ? $opts{b} + 0 : 3;
      my $after  = (defined $opts{f}) ? $opts{f} + 0 : 3;
      
      print "# before = $before; after = $after\n" if debug;
      
      my @lines = (); # Accumulated lines
      my $tail  = 0;  # Line number of last line in list
      my $tbp_1 = 0;  # First line to be printed
      my $tbp_2 = 0;  # Last line to be printed
      
      # Print lines from @lines in the range $tbp_1 .. $tbp_2,
      # leaving $leave lines in the array for future use.
      sub print_leaving
      {
          my ($leave) = @_;
          while (scalar(@lines) > $leave)
          {
              my $line = shift @lines;
              my $curr = $tail - scalar(@lines);
              if ($tbp_1 <= $curr && $curr <= $tbp_2)
              {
                  print "$ARGV:" if $opts{F};
                  print "$curr:" if $opts{n};
                  print $line;
              }
          }
      }
      
      # General logic:
      # Accumulate each line at end of @lines.
      # ** If current line matches, record range that needs printing
      # ** When the line array contains enough lines, pop line off front and,
      #    if it needs printing, print it.
      # At end of file, empty line array, printing requisite accumulated lines.
      
      while (<>)
      {
          # Add this line to the accumulated lines
          push @lines, $_;
          $tail = $.;
      
          printf "# array: N = %d, last = $tail: %s", scalar(@lines), $_ if debug > 1;
      
          if (m/$op/o)
          {
              # This line matches - set range to be printed
              my $lo = $. - $before;
              $tbp_1 = $lo if ($lo > $tbp_2);
              $tbp_2 = $. + $after;
              print "# $. MATCH: print range $tbp_1 .. $tbp_2\n" if debug;
          }
      
          # Print out any accumulated lines that need printing
          # Leave $before lines in array.
          print_leaving($before);
      }
      continue
      {
          if (eof)
          {
              # Print out any accumulated lines that need printing
              print_leaving(0);
              # Reset for next file
              close ARGV;
              $tbp_1 = 0;
              $tbp_2 = 0;
              $tail  = 0;
              @lines = ();
          }
      }
      

      【讨论】:

        【解决方案4】:

        我遇到过一种情况,我在平板电脑上遇到了缓慢的 telnet 会话,信不信由你,而且我无法使用该键盘轻松编写 Perl 脚本。我想出了这个在 AIX 有限的 grep 中对我来说非常有用的 hacky 策略。如果您的 grep 返回数百行,这将无法正常工作,但如果您只需要一行和上/下一两行,则可以这样做。首先我运行了这个:

        cat -n filename |grep criteria

        通过包含-n 标志,我可以看到我正在寻找的数据的行号,如下所示:

        2543 my crucial data
        

        由于cat 在行号之前和之后分别给出了 2 个空格和 1 个空格,因此我可以像这样使用 grep 获取 行号

        cat -n filename |grep " 2542 "

        我运行了几次,给我第 2542 行和第 2544 行,第 2543 行被预定。就像我说的,这绝对是错误的,就像如果你有大量数据可能到处都是“2542”,但只是抓住几条快速线,效果很好。

        【讨论】:

          猜你喜欢
          • 2014-08-16
          • 2013-01-19
          • 2015-07-02
          • 1970-01-01
          • 2015-02-20
          • 1970-01-01
          • 2012-09-08
          • 2021-02-13
          • 2014-10-12
          相关资源
          最近更新 更多