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?
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?
Respuestas:
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
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.