Conta il numero totale di righe prima / dopo una corrispondenza del modello


9

Sto avendo un lungo elenco di indirizzi IP, che non sono in sequenza. Devo trovare quanti indirizzi IP ci sono prima / dopo un determinato indirizzo IP. Come posso raggiungere questo obiettivo?


Hai un IP duplicato?
cuonglm,

No. Tutti gli indirizzi IP sono univoci.
Mandar Shinde,

Cosa significa prima / dopo per un indirizzo IP? In particolare, hai indirizzi IPv4 e IPv6? Come si confrontano?
vinc17,

Hai bisogno del file ordinato?
cuonglm,

2
@ vinc17 - Il file contiene solo indirizzi IP (IPv4), nessun altro dato è incluso. Se ci sono 1000 indirizzi IP in totale e la corrispondenza si trova nella 300esima posizione, significa che ci sono 299 linee prima della partita e 700 linee dopo la partita.
Mandar Shinde,

Risposte:


8

Numero di righe prima e dopo una partita, inclusa la partita (ad esempio, è necessario sottrarre 1 dal risultato se si desidera escludere la partita):

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

Ma questo non ha nulla a che fare con gli indirizzi IP in particolare.


4

Forse il più semplice è,

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

Grazie @JoshepR per aver segnalato l'errore


Questo stampa solo il numero di riga su cui si è verificato il motivo.
Joseph R.,

@JosephR. - no, stampa ogni numero di riga su cui si verifica ogni corrispondenza.
Mikeserv,

@mikeserv Lo so ma l'OP ha specificato che gli indirizzi IP sono univoci. L'OP inoltre non vuole il numero di riga in cui si sono verificate le corrispondenze; vogliono il numero di linee prima che si verifichi il motivo e il numero di linee dopo di esso.
Joseph R.,

@JosephR - il modo più veloce per arrivare a quei conteggi è calcolare i numeri di riga - lo farei direttamente direttamente a dcme stesso, probabilmente.
Mikeserv,

@mikeserv Non sto sostenendo che le informazioni da questa risposta non siano utili, sto solo dicendo che questo codice da solo non fa ciò che l'OP vuole.
Joseph R.,

3

L'ho fatto in due modi, anche se penso che mi piaccia di più:

: $(( 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

Ciò salva tutte quelle come variabili shell correnti e le valuta successivamente nel ciclo for per l'output. Conta le linee totali nel file wce ottiene il primo numero di riga corrispondente sed.

Il suo output:

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

Ho anche fatto:

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

sedstampa solo i numeri corrispondenti e dell'ultima riga, quindi trtraduce le \newline intermedie ine readlegge il primo dei sedrisultati in $mle tutti gli altri in $ll. Le possibili casistiche multiple vengono gestite rimuovendo tutto tranne l'ultimo risultato $lldall'espansione quando lo si imposta nuovamente in un secondo momento.

Il suo output:

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

Entrambi i metodi sono stati testati sul file generato nel modo seguente:

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 

Lo fa, per numero di riga:

  1. imposta la stringa di ricerca
  2. esegue il ciclo cinque volte per garantire che vi siano più corrispondenze
  3. stampa 199 zero e "$IP"poi una \newline
  4. output dei tubi a tr- che traduce gli zero in \newline e poi in~/file

2

Ecco un po 'di codice Perl che lo fa:

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

Questo conta il numero totale di righe prima e dopo la riga che contiene l'IP 192.168.1.1. Sostituisci con il tuo IP desiderato.

Utilizzando nient'altro che 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 è preferito.
Mandar Shinde,

2
@Joseph R .: Perché non usi $.un contatore?
cuonglm,

@Gnouc, ovviamente. Penso solo che questo è più leggibile rispetto impostazione $aftera $. - $before.
Joseph R.,

No, intendo: se abbinato, stampa $. - 1, salva $.su $tmp. Fine stampa $. - $tmp. Quindi non abbiamo bisogno di un contatore per entrambi prima e dopo. Ovviamente è meno leggibile del tuo.
cuonglm,

@MandarShinde Vedi la modifica. Ho aggiunto una pura risposta Bash.
Joseph R.,

2

Stavo provando i seguenti comandi, che sono un po 'complicati, ma darei risultati accurati:

Dopo:

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

Prima:

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

2

Una awksoluzione che riporta il numero di righe prima e dopo l'ultima corrispondenza

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

1

Grepha una funzione che può contare il numero di volte in cui viene trovato un modello particolare. Se si utilizza il -ccomando che lo farà. Con il comando -ce -v, questo conterà quante volte ciò non corrisponde a un modello particolare

Esempio:

grep -c -v <pattern> file

Quindi se provi qualcosa del genere:

grep -c -v 192.168.x.x file.log dovrebbe funzionare.


Questo conta il numero di occorrenze dell'IP target. Questo non è ciò che l'OP ha richiesto.
Joseph R.,

L'ho appena modificato, se sta chiedendo di contare tutti gli altri IP prima e dopo un determinato IP, la modifica dovrebbe funzionare per lui.
Ryekayo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.