0

我想在匹配模式之前和之后提取行。

eg:如果文件内容如下

absbasdakjkglksagjgj
sajlkgsgjlskjlasj
hello
lkgjkdsfjlkjsgklks
klgdsgklsdgkldskgdsg

我需要在'hello'之前和之后找到你好并显示行

输出应该是

sajlkgsgjlskjlasj
hello
lkgjkdsfjlkjsgklks

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

4

4 回答 4

1
sed -n '/hello/{x;G;N;p;};h' filename
于 2013-09-25T23:18:53.690 回答
0

我发现构建 GNU coreutils 一次通常不会那么令人沮丧,并受益于更多功能http://www.gnu.org/software/coreutils/

于 2013-09-26T14:09:26.510 回答
0

由于您将在机器上安装 Perl,因此您可以使用以下代码,但安装 GNU 实用程序可能会更好。这具有匹配-b n1-f n1行和匹配后行的选项。它适用于 PCRE 匹配(因此,如果您想要不区分大小写的匹配,i请在正则表达式之后添加一个,而不是使用-i选项。我没有实现-vor -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 = ();
    }
}
于 2013-09-26T14:17:57.557 回答
0

我有一种情况,我在平板电脑上遇到缓慢的 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”,但只是为了抓住一个几条快速线,效果很好。

于 2015-05-16T01:15:48.843 回答