パターン一致の前後の行の総数をカウントする


9

順番に並んでいないIPアドレスの長いリストがあります。特定のIPアドレスの前後にIPアドレスがいくつあるかを調べる必要があります。どうすればこれを達成できますか?


IPが重複していますか?
cuonglm 2014

いいえ。すべてのIPアドレスは一意です。
Mandar Shinde

IPアドレスの前後はどういう意味ですか?特に、IPv4アドレスとIPv6アドレスの両方を持っていますか?彼らはどのように比較しますか?
vinc17 14

ファイルをソートする必要がありますか?
cuonglm 2014

2
@ vinc17-ファイルにはIPアドレス(IPv4)のみが含まれ、他のデータは含まれません。合計で1000個のIPアドレスがあり、一致が300番目の場所で見つかった場合、一致の前に299行、一致の後に700行あることを意味します。
Mandar Shinde 14

回答:


8

一致を含む、一致前後の行数(一致を除外する場合は、結果から1を引く必要があります):

sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l

ただし、これは特にIPアドレスとは関係ありません。


4

多分最も簡単なのは、

sed -n '/pattern/{=; q;}' file

エラーを指摘してくれた@JoshepRに感謝


これは、パターンが発生した行番号を出力するだけです。
ジョセフR.

@JosephR。-いいえ、すべての一致が発生するすべての行番号を出力します。
mikeserv 2014

@mikeserv知っていますが、OP はIPアドレスが一意であることを指定しました。OPは、一致が発生した行番号も必要としません。彼らがしたい行数パターンが発生する前その後の行数を。
ジョセフR.

@JosephR-これらのカウントに到達する最も早い方法は、行番号を集計することです-私はdcおそらくこれを直接、私自身に直接パイプします。
mikeserv 2014

@mikeservこの回答からの情報が役に立たないと主張しているのではなく、このコードだけではOPが望んでいることを実行しないと言っているだけです。
ジョセフR.

3

私はこれを2つの方法で行いましたが、これが一番好きだと思います。

: $(( afterl=( lastl=$(wc -l <~/file) ) - 2 -
  $(( beforel=( matchl=$(sed -n "/$IP/{=;q;}" <~/file) ) - 1
)) ))
for n in last match afters befores
do  printf '%s line%s :\t%d\n' \
        "${n%s}" "${n##*[!s]}" $((${n%s}l))
done

これにより、それらすべてが現在のシェル変数として保存され、その後forループで評価されて出力されます。ファイル内の合計行数をカウントしwc、で最初に一致した行番号を取得しsedます。

その出力:

last line :     1000
match line :    200
after lines :   799
before lines :  199

私もしました:

sed -n "/$IP/=;\$=" ~/file |  
tr \\n \  | { 
IFS=' ' read ml ll 
printf '%s line%s:\t%d\n' \
    last '' $((ll=${ll##* }))
    match '' $ml \
    after s "$((al=ll-ml-1)) \ 
    before s $((bl=ml-1))
}

sed一致する最後の行番号のみを出力しtr、間にある\newlinesを次のように変換します。、とreadの最初の読み込みsedさんへの結果$mlに、他のすべてを$ll。複数の一致の可能性があるケースは、$ll後で再度設定するときに、の展開から最後の結果を除いてすべてを取り除くことによって処理されます。

その出力:

last line :     1000
match line :    200
after lines :   799
before lines :  199

どちらの方法も、次の方法で生成されたファイルでテストされました。

IP='some string for which I seek' 
for count in 1 2 3 4 5 
do  printf '%.199d%s\n' 0 "$IP" 
done | tr 0 \\n >~/file 

それは行番号で:

  1. 検索文字列を設定します
  2. 5回ループして、複数の一致があることを確認します
  3. 199個のゼロを出力し、"$IP"次に\newlineを出力します
  4. パイプ出力tr-ゼロを\newlineに変換し、次に~/file

2

これを行うPerlコードの一部を次に示します。

perl -ne '
     if(1 .. /192\.168\.1\.1/) { $before++ }
     else                      { $after++  }
     $before--; # The matching line was counted
     END{print "Before: $before, After: $after\n"}' your_file

これは、IPを含む行の前後の行の総数をカウントします192.168.1.1。希望のIPに置き換えます。

Bashのみを使用:

before=0
match=0
after=0
while read line;do
    if [ "$line" = 192.168.1.1 ];then
        match=1
    elif [ $match -eq 0 ];then
        before=$(($before+1))
    else
        after=$(($after + 1))
    fi
done < your_file
printf "Before: %d, After: %d\n" "$before" "$after"

BASHが推奨されます。
Mandar Shinde 14

2
@Joseph R .: $.カウンターの代わりに使ってみませんか?
cuonglm 2014

@Gnoucもちろんできます。これはに設定$afterするよりも読みやすいと思います$. - $before
ジョセフR.

いいえ、つまり、一致した場合は、印刷して$. - 1に保存$.$tmpます。印刷を終了します$. - $tmp。そのため、前後の両方にカウンターは必要ありません。もちろんそれはあなたのものよりも読みにくいです。
cuonglm 2014

@MandarShinde編集をご覧ください。純粋なBashの回答を追加しました。
ジョセフR.

2

次のコマンドを試してみましたが、少し複雑ですが、正確な結果が得られます。

後:

a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l

前:

echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l

2

awk最後の一致の前後の行数を報告するソリューション

awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}'  file

1

Grep特定のパターンが見つかった回数をカウントできる機能があります。そうする-cコマンドを使用する場合。-cand -vコマンドを使用すると、これが特定のパターンに一致しない回数がカウントされます

例:

grep -c -v <pattern> file

したがって、次のようなことを試した場合:

grep -c -v 192.168.x.x file.log それはうまくいくはずです。


これは、ターゲットIPの発生数をカウントします。これはOPが要求したものではありません。
ジョセフR.

私はそれを編集しました。彼が特定のIPの前後にある他のすべてのIPをカウントするように求めている場合、編集は彼のために機能するはずです。
ryekayo 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.