J'ai une longue liste d'adresses IP, qui ne sont pas en séquence. J'ai besoin de trouver combien d'adresses IP sont là avant / après une adresse IP particulière. Comment puis-je atteindre cet objectif?
J'ai une longue liste d'adresses IP, qui ne sont pas en séquence. J'ai besoin de trouver combien d'adresses IP sont là avant / après une adresse IP particulière. Comment puis-je atteindre cet objectif?
Réponses:
Nombre de lignes avant et après une correspondance, y compris la correspondance (c'est-à-dire que vous devez soustraire 1 du résultat si vous souhaitez exclure la correspondance):
sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l
Mais cela n'a rien à voir avec les adresses IP en particulier.
Le plus simple est peut-être
sed -n '/pattern/{=; q;}' file
Merci @JoshepR d'avoir signalé l'erreur
dc
moi-même, probablement.
J'ai fait cela de deux façons, bien que je pense que j'aime le mieux:
: $(( 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
Cela les enregistre en tant que variables shell actuelles - et les évalue ensuite dans la boucle for pour la sortie. Il compte le nombre total de lignes dans le fichier avec wc
et obtient le premier numéro de ligne correspondant avec sed
.
Sa sortie:
last line : 1000
match line : 200
after lines : 799
before lines : 199
J'ai aussi fait:
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
imprime uniquement les numéros correspondants et de dernière ligne, puis tr
traduit les \n
lignes électroniques intermédiaires en, et read
lit le premier des sed
résultats dans $ml
et tous les autres dans $ll
. Les cas de correspondance multiples possibles sont traités en supprimant tout sauf le dernier résultat de $ll
l'expansion de lorsque vous le redéfinissez plus tard.
Sa sortie:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Les deux méthodes ont été testées sur le fichier généré de la manière suivante:
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
Il le fait, par numéro de ligne:
"$IP"
puis un \n
ewlinetr
- ce qui traduit les zéros en \n
ewlines puis en~/file
Voici un peu de code Perl qui le fait:
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
Cela compte le nombre total de lignes avant et après la ligne contenant l'IP 192.168.1.1
. Remplacez par votre IP souhaitée.
N'utiliser que 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"
$.
place d'un compteur?
$after
à $. - $before
.
$. - 1
, enregistrez $.
dans $tmp
. Fin de l'impression $. - $tmp
. Nous n'avons donc pas besoin de compteur avant et après. Bien sûr, il est moins lisible que le vôtre.
J'essayais les commandes suivantes, qui sont un peu compliquées, mais donneraient des résultats précis:
Après:
a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l
Avant:
echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l
Grep
a une fonction qui peut compter le nombre de fois où un motif particulier est trouvé. Si vous utilisez la -c
commande qui le fera. Avec la commande -c
et -v
, cela comptera combien de fois cela ne correspond pas à un modèle particulier
Exemple:
grep -c -v <pattern> file
Donc, si vous essayez quelque chose comme:
grep -c -v 192.168.x.x file.log
Cela devrait fonctionner.