-A
-B
-C
grep キーワードの前後のコンテキストを表示するために使用できることはわかっています。
私の質問は、異なるキーワードで異なるコンテキストを表示するにはどうすればよいですか?
たとえば、-A 5
猫、-B 4
犬、-C 1
猿を表示するにはどうすればよいですか。
egrep -A3 "cat|dog|monkey" <file>
// this just show 3 after lines for each keyword.
単一のgrep呼び出しでそれを行う方法はないと思いますが、変数ごとに1回grepを実行して出力を連結できます:
var=$(grep -n -A 5 cat file)$'\n'$(grep -n -B 4 dog file)$'\n'$(grep -n -C 1 monkey file)
var=$(sort -un <(echo "$var"))
これecho "$var"
で、単一のコマンドから取得したものと同じ出力に加えて、行番号とコンテキスト インジケーターが生成されます (:
接頭辞は、パターンに正確に一致した行を示し、接頭辞はand/orオプション-
のために含まれている行を示します) .-A
-B
-C
これまでに行番号を含めた理由は、1 つのステートメントでこれを行うことができた場合に表示される結果の順序を維持するためです。気に入った場合は素晴らしいですが、そうでない場合は、次の行を使用してそれらを切り取ることができます。
var=$(cut -d: -f2- <(echo "$var") | cut -d- -f2-)
これは、完全に一致する行のプレフィックスをカットするために一度通過し、次にコンテキスト一致のプレフィックスをカットするためにもう一度通過します。
かわいい?番号。しかし、それは機能します。
私はgrep
それをしないと思います。別のツールを使用する必要があります。おそらく、独自のプログラムを作成します。
このような何かがそれをするでしょう:
awk '
BEGIN{ ARGV[ARGC++] = ARGV[1] }
function prtB(nr) { for (i=FNR-nr; i<FNR; i++) print a[i] }
function prtA(nr) { for (i=FNR+1; i<=FNR+nr; i++) print a[i] }
NR==FNR{ a[NR]; next }
/cat/ { print; prtA(5) }
/dog/ { prtB(4); print }
/monkey/ { prtB(1); print; prtA(1) }
' file
関数のループの計算を確認してください。たとえば、猿と犬を含む行をどのように処理するかについては言いませんでした。
編集:これは、一致するものの周りに最大のコンテキストを出力し、コマンドラインでコンテキストを指定できるようにし、上記の安価で陽気なソリューションほど多くのメモリを使用しない、テストされていないソリューションです:
awk -v cxts="cat:0:5\ndog:4:0\nmonkey:1:1" '
BEGIN{
ARGV[ARGC++] = ARGV[1]
numCxts = split(cxts,cxtsA,RS)
for (i=1;i<=numCxts;i++) {
regex = cxtsA[i]
n = split(regex,rangeA,/:/)
sub(/:[^:]+:[^:]+$/,"",regex)
endA[regex] = rangeA[n]
startA[regex] = rangeA[n-1]
regexA[regex]
}
}
NR==FNR{
for (regex in regexA) {
if ($0 ~ regex) {
start = NR - startA[regex]
end = NR + endA[regex]
for (i=start; i<=end; i++) {
prt[i]
}
}
}
next
}
FNR in prt
' file
cxts変数で検索されたパターンを、RS値(デフォルトでは改行)で区切ります。