On AIX, grep -B -A -m does not work. Any solution with sed or awk

I am on an AIX system. But grepon AIX does not support -B, -A, -Mon AIX. Are there other solutions, such as awkor sed, that can do the same job?

For instance:

str1
str2
str3
str4
str9
str8
str1
str3
str2

I am trying to run grep str3 -m 1 -B 1 -A 1to get:

str2
str3
str4

but it does not work on AIX. Is there a solution for sedor awk?

+3
source share
6 answers
 awk 'c&&c--;/str3/{print p;print $0;c=1}{p=$0}' file
+2
source

You can use the circular buffer that you print when a match is found, and then the corresponding line, and then additional lines.

#!/usr/bin/awk -f
BEGIN {
    B = 4              # set these values like you would use for grep -B, -A, -m
    A = 2
    m = 3

    patt = "999"       # set this to your regex

    i = 0
    B++                # the buffer will hold B lines plus one for the match
}

{
    a[i] = $0          # accumulate B (+1) lines in a circular buffer
    i = (i + 1) % B
}

$0 ~ patt {            # if the pattern is found print the contents of the buffer
    for (j=1; j<=B; j++) {
        print a[i]
        i = (i + 1) % B
    }
    split("", a)
    for (i=1; i<=A; i++) {    # print the next A lines
        getline
        print
    }
    if (--m == 0) exit        # output m matches then quit
    print "---"
}

script , , .

, AWK -v.

+3

, +1 . , ...

ed (1).

so ross$ cat >> cg.ed
/str3/-1;.+2p
so ross$ ed - cg.txt < cg.ed
str2
str3
str4
so ross$ 

script , :

so ross$ cat > cg.sh
#!/bin/sh
ed - $1 << eof
/$2/-1;.+2p
eof
so ross$ sh cg.sh cg.txt str3
str2
str3
str4
so ross$ 
+2

78- script, . 114- Perl script, GNU grep, . script - ​​ (AFAIK, GNU grep, , , GNU grep).

#!/bin/ksh
#
# @(#)$Id: old.sgrep.sh,v 1.5 2007/09/15 22:15:43 jleffler Exp $
#
#   Special grep
#   Finds a pattern and prints lines either side of the pattern
#   Line numbers are always produced by ed (substitute for grep),
#   which allows us to eliminate duplicate lines cleanly.  If the
#   user did not ask for numbers, these are then stripped out.
#
#   BUG: if the pattern occurs in in the first line or two and
#   the number of lines to go back is larger than the line number,
#   it fails dismally.

set -- `getopt "f:b:hn" "$@"`

case $# in
0)  echo "Usage: $0 [-hn] [-f x] [-b y] pattern [files]" >&2
    exit 1;;
esac

# Tab required - at least with sed (perl would be different)
# But then the whole problem would be different if implemented in Perl.
number="'s/^\\([0-9][0-9]*\\)   /\\1:/'"
filename="'s%^%%'"      # No-op for sed

f=3
b=3
nflag=no
hflag=no
while [ $# -gt 0 ]
do
    case $1 in
    -f) f=$2; shift 2;;
    -b) b=$2; shift 2;;
    -n) nflag=yes; shift;;
    -h) hflag=yes; shift;;
    --) shift; break;;
    *)  echo "Unknown option $1" >&2
        exit 1;;
    esac
done
pattern="${1:?'No pattern'}"
shift

case $# in
0)  tmp=${TMPDIR:-/tmp}/`basename $0`.$$
    trap "rm -f $tmp ; exit 1" 0
    cat - >$tmp
    set -- $tmp
    sort="sort -t: -u +0n -1"
    ;;
*)  filename="'s%^%'\$file:%"
    sort="sort -t: -u +1n -2"
    ;;
esac

case $nflag in
yes)    num_remove='s/[0-9][0-9]*://';;
no)     num_remove='s/^//';;
esac
case $hflag in
yes)    fileremove='s%^$file:%%';;
no)     fileremove='s/^//';;
esac

for file in $*
do
    echo "g/$pattern/.-${b},.+${f}n" |
    ed - $file |
    eval sed -e "$number" -e "$filename" |
    $sort |
    eval sed -e "$fileremove" -e "$num_remove"
done

rm -f $tmp
trap 0
exit 0
+2

this little coding will highlight the regex and will work like grep -A -B -m Hope this helps.

Christian Knauer

#!/bin/bash
[ $# -lt 2 ] && printf "usage: %s <regex> <file> [[[back]forward]occurrence] \n" "$0" && exit 0
REGEX=$1
FILE=$2
BACK=${3:-1}
FORWARD=${4:-1}
STOP=${5:-1000000000}
awk -v bold=$'\e[1m' -v norm=$'\e[0m' -v back=$BACK -v forward=$FORWARD -v stop=$STOP 'BEGIN {cnt=0} { array[i++]=$0 }
     END {
       maxI=++i
       for (j=0;j<maxI; j++) {
         if (array[j] ~ /'"${REGEX}"'/) {
           for (z=back;z>0; z--) {
             print array[j-z]
           }
           printf bold > "/dev/stderr"
           printf("%s\n", array[j])
           printf norm > "/dev/stderr"
           for (x=1;x<=forward; x++) {
             print array[j+x]
           }
           cnt++
           if (cnt == stop) {
             break
           }
         }
       }
     }
   ' "$FILE"
+1
source

DigitallRoss answer is a little simplified , which additionally prints ALL the relevant lines, and not just the first one matching the pattern str3:

echo ',g/str3/-1;+2p' | ed - myFile.txt 

Where

,                 # read all lines (from first to the very last)
 g/str3/          # search for `str3` string
        -1        # take 1 line BEFORE the matching one
          ;+2     # and also next 2 lines (so 3 lines in total)
             p    # and print them

If you want to print only FIRST, then the command is simpler:

echo '/str3/-1;+2p' | ed - myFile.txt

Where

/str3/          # find line matching the `str3` string
      -1        # take 1 line BEFORE the matching one
        ;+2     # and also next 2 lines (so 3 lines in total)
           p    # and print them
+1
source

Source: https://habr.com/ru/post/1793522/


All Articles