在AIX上,grep -B -A -m不起作用。任何解决方案与sed或awk

时间:2011-02-21 06:08:50

标签: shell

我在AIX系统上。但AIX上的grep不支持AIX系统上的-B-A-M。还有其他解决方案,例如awksed可以执行相同的工作吗?

例如:

str1
str2
str3
str4
str9
str8
str1
str3
str2

我尝试运行grep str3 -m 1 -B 1 -A 1来获取:

str2
str3
str4

但它在AIX上不起作用。是否有sedawk的解决方案?

7 个答案:

答案 0 :(得分:3)

您可以使用在找到匹配项时打印的循环缓冲区,然后是匹配的行,然后是其他行。

#!/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 "---"
}

更复杂的脚本会接受选项和参数,而不必编辑它来更改它们。

作为妥协,你可以重新安排一些事情并使用AWK的-v选项传递参数。

答案 1 :(得分:2)

顺便说一下,祝贺和+1提供样本输入和输出。你会惊讶地发现有多少问题缺少这些明显的规范......

这可以用ed(1)完成。

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

您可以创建一个脚本,将文件名和模式作为参数:

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 :(得分:2)

 awk 'c&&c--;/str3/{print p;print $0;c=1}{p=$0}' file

答案 3 :(得分:2)

我有一个78行的shell脚本来完成这项工作。我后来用一个114行的Perl脚本替换它,但通常是我需要设施的端口GNU grep。 shell脚本如下 - 它对选项使用了不同的命名法(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

答案 4 :(得分:1)

这个小编码将突出显示正则表达式并且像grep -A -B -m一样工作 希望这会有所帮助。

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"

答案 5 :(得分:1)

略微简化DigitallRoss' answer,另外打印所有匹配的行,不仅是第一个匹配str3模式:

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

,其中

,                 # 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

如果您只想打印第一次出现,那么命令就更简单了:

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

,其中

/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

答案 6 :(得分:0)

如果str9之后需要3行,这很简单

输入文件

$cat <<'EOF' > strfile.txt
str1
str2
str3
str4
str9
str8
str1
str3
str2
EOF

搜索str9并打印+ 3行(包括文件名。在搜索大量文件* .txt时很方便

$awk '/str9/{print FILENAME;n=NR+3} n>=NR' strfile.txt

strfile.txt
str9
str8
str1
str3