Ich habe eine lange Liste von IP-Adressen, die nicht der Reihe nach sind. Ich muss herausfinden, wie viele IP-Adressen vor / nach einer bestimmten IP-Adresse vorhanden sind. Wie kann ich das erreichen?
Ich habe eine lange Liste von IP-Adressen, die nicht der Reihe nach sind. Ich muss herausfinden, wie viele IP-Adressen vor / nach einer bestimmten IP-Adresse vorhanden sind. Wie kann ich das erreichen?
Antworten:
Anzahl der Zeilen vor und nach einer Übereinstimmung, einschließlich der Übereinstimmung (dh Sie müssen 1 vom Ergebnis abziehen, wenn Sie die Übereinstimmung ausschließen möchten):
sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l
Dies hat jedoch insbesondere nichts mit IP-Adressen zu tun.
Vielleicht ist das einfachste,
sed -n '/pattern/{=; q;}' file
Vielen Dank an @JoshepR für den Hinweis auf den Fehler
dc
wahrscheinlich direkt an mich selbst weiterleiten .
Ich habe das auf zwei Arten gemacht, obwohl ich denke, dass mir das am besten gefällt:
: $(( 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
Das speichert all diese als aktuelle Shell-Variablen - und wertet sie anschließend in der for-Schleife für die Ausgabe aus. Es zählt die Gesamtzahl der Zeilen in der Datei mit wc
und erhält die erste übereinstimmende Zeilennummer mit sed
.
Seine Ausgabe:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Ich habe auch getan:
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
druckt nur übereinstimmende und letzte Zeilennummern und tr
übersetzt dann die dazwischen liegenden \n
Zeilen inund read
liest die ersten sed
Ergebnisse in $ml
und alle anderen in $ll
. Mögliche Fälle mit mehreren Übereinstimmungen werden behandelt, indem alle bis auf das letzte Ergebnis aus der $ll
Erweiterung entfernt werden, wenn sie später erneut festgelegt werden.
Seine Ausgabe:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Beide Methoden wurden an der auf folgende Weise generierten Datei getestet:
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
Nach Zeilennummer:
"$IP"
dann eine \n
Ewlinetr
- übersetzt Nullen in \n
ewlines und dann in~/file
Hier ist ein bisschen Perl-Code, der das macht:
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
Dies zählt die Gesamtzahl der Zeilen vor und nach der Zeile, die die IP enthält 192.168.1.1
. Ersetzen Sie durch Ihre gewünschte IP.
Verwenden Sie nur 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"
$.
anstelle eines Zählers?
$after
auf $. - $before
.
$. - 1
, speichern $.
unter $tmp
. Druck beenden $. - $tmp
. Wir brauchen also keinen Zähler für vorher und nachher. Natürlich ist es weniger lesbar als deins.
Ich habe die folgenden Befehle ausprobiert, die etwas kompliziert sind, aber genaue Ergebnisse liefern würden:
Nach dem:
a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l
Vor:
echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l
Grep
hat eine Funktion, die zählen kann, wie oft ein bestimmtes Muster gefunden wird. Wenn Sie den -c
Befehl verwenden, wird dies getan. Mit dem -c
und -v
Befehl, diese zählen , wie oft dies nicht ein bestimmtes Muster überein
Beispiel:
grep -c -v <pattern> file
Also, wenn Sie etwas versuchen wie:
grep -c -v 192.168.x.x file.log
das sollte funktionieren.