Compter le nombre total de lignes avant / après une correspondance de modèle

9

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?

Mandar Shinde
la source
Avez-vous une adresse IP en double?
cuonglm
Non. Toutes les adresses IP sont uniques.
Mandar Shinde
Que signifie avant / après pour une adresse IP? En particulier, avez-vous des adresses IPv4 et IPv6? Comment se comparent-ils?
vinc17
Avez-vous besoin de trier le fichier?
cuonglm
2
@ vinc17 - Le fichier contient uniquement des adresses IP (IPv4), aucune autre donnée n'est incluse. S'il y a 1000 adresses IP au total et que la correspondance est trouvée au 300e emplacement, cela signifie qu'il y a 299 lignes avant la correspondance et 700 lignes après la correspondance.
Mandar Shinde

Réponses:

8

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.

vinc17
la source
4

Le plus simple est peut-être

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

Merci @JoshepR d'avoir signalé l'erreur

jpmuc
la source
Cela imprime simplement le numéro de ligne sur lequel le motif s'est produit.
Joseph R.
@JosephR. - non, il imprime chaque numéro de ligne sur lequel chaque correspondance se produit.
mikeserv
@mikeserv Je sais mais l'OP a précisé que les adresses IP sont uniques. L'OP ne veut pas non plus du numéro de ligne où la correspondance s'est produite; ils veulent le nombre de lignes avant que le motif ne se produise et le nombre de lignes après.
Joseph R.
@JosephR - le moyen le plus rapide pour arriver à ces décomptes est de faire le décompte des numéros de ligne - je dirais simplement ceci directement à dcmoi-même, probablement.
mikeserv
@mikeserv Je ne dis pas que les informations de cette réponse ne sont pas utiles, je dis simplement que ce code à lui seul ne fait pas ce que l'OP veut.
Joseph R.
3

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 wcet 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))
}

sedimprime uniquement les numéros correspondants et de dernière ligne, puis trtraduit les \nlignes électroniques intermédiaires en, et readlit le premier des sedrésultats dans $mlet tous les autres dans $ll. Les cas de correspondance multiples possibles sont traités en supprimant tout sauf le dernier résultat de $lll'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:

  1. définit la chaîne de recherche
  2. boucle cinq fois pour s'assurer qu'il y aura plusieurs correspondances
  3. imprime 199 zéros "$IP"puis un \newline
  4. tubes sortie vers tr- ce qui traduit les zéros en \newlines puis en~/file
mikeserv
la source
2

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"
Joseph R.
la source
BASH est préféré.
Mandar Shinde
2
@Joseph R .: Pourquoi n'utilisez-vous pas à la $.place d'un compteur?
cuonglm
@Gnouc je pourrais bien sûr. Je pense simplement que c'est plus lisible que de se mettre $afterà $. - $before.
Joseph R.
Non, je veux dire: si assorti, imprimez $. - 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.
cuonglm
@MandarShinde Veuillez voir la modification. J'ai ajouté une pure réponse Bash.
Joseph R.
2

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
Mandar Shinde
la source
2

Une awksolution rapportant le nombre de lignes avant et après la dernière correspondance

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

Grepa une fonction qui peut compter le nombre de fois où un motif particulier est trouvé. Si vous utilisez la -ccommande qui le fera. Avec la commande -cet -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.

ryekayo
la source
Cela compte le nombre d'occurrences de l'IP cible. Ce n'est pas ce que le PO a demandé.
Joseph R.
Je viens de l'éditer, s'il demande de compter toutes les autres IP avant et après une IP particulière, l'édition devrait fonctionner pour lui.
ryekayo