我在AIX系统上。但AIX上的grep
不支持AIX系统上的-B
,-A
,-M
。还有其他解决方案,例如awk
或sed
可以执行相同的工作吗?
例如:
str1
str2
str3
str4
str9
str8
str1
str3
str2
我尝试运行grep str3 -m 1 -B 1 -A 1
来获取:
str2
str3
str4
但它在AIX上不起作用。是否有sed
或awk
的解决方案?
答案 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