Tengo una larga lista de direcciones IP, que no están en secuencia. Necesito encontrar cuántas direcciones IP hay antes / después de una dirección IP en particular. ¿Cómo puedo conseguir esto?
fuente
Tengo una larga lista de direcciones IP, que no están en secuencia. Necesito encontrar cuántas direcciones IP hay antes / después de una dirección IP en particular. ¿Cómo puedo conseguir esto?
Número de líneas antes y después de una coincidencia, incluida la coincidencia (es decir, debe restar 1 del resultado si desea excluir la coincidencia):
sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l
Pero esto no tiene nada que ver con las direcciones IP en particular.
Quizás lo más fácil es,
sed -n '/pattern/{=; q;}' file
Gracias @JoshepR por señalar el error
dc
; probablemente lo dirija directamente a mí mismo, probablemente.
Lo hice de dos maneras, aunque creo que me gusta más:
: $(( 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
Eso los guarda a todos como variables de shell actuales, y luego los evalúa en el ciclo for para la salida. Cuenta el total de líneas en el archivo wc
y obtiene el primer número de línea coincidente con sed
.
Su salida:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Yo también hice:
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 solo los números coincidentes y de la última línea, luego tr
traduce las \n
líneas electrónicas intermedias a, y read
lee el primero de sed
los resultados en $ml
y todos los demás en $ll
. Los posibles casos de coincidencias múltiples se manejan eliminando todos los resultados, excepto el último, de $ll
la expansión cuando se configura de nuevo más tarde.
Su salida:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Ambos métodos fueron probados en el archivo generado de la siguiente manera:
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 hace, por número de línea:
"$IP"
luego una línea \n
electrónicatr
- que traduce ceros a \n
líneas de flujo y luego~/file
Aquí hay un poco de código Perl que lo hace:
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
Esto cuenta el número total de líneas antes y después de la línea que contiene la IP 192.168.1.1
. Reemplace con su IP deseada.
Usando nada más 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"
$.
lugar de un contador?
$after
a $. - $before
.
$. - 1
, guarde $.
en $tmp
. Fin de impresión $. - $tmp
. Por lo tanto, no necesitamos un contador para ambos antes y después. Por supuesto, es menos legible que el tuyo.
Estaba probando los siguientes comandos, que son un poco complicados, pero darían resultados precisos:
Después:
a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l
Antes de:
echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l
Una awk
solución que informa el número de líneas antes y después del último partido
awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}' file
Grep
tiene una función que puede contar la cantidad de veces que se encuentra un patrón en particular. Si usa el -c
comando, lo hará. Con el comando -c
y -v
, esto contará cuántas veces esto no coincide con un patrón en particular
Ejemplo:
grep -c -v <pattern> file
Entonces, si intentas algo como:
grep -c -v 192.168.x.x file.log
eso debería funcionar.