Saltar al contenido

Use AWK para leer duplicados en una columna

Solución:

Usando GNU awk para mktime ():

$ cat tst.awk
BEGIN { FS = "|" }
(++count[$2]) ~ /^[15]$/ {
    split($1,t,"[/:]")
    monthNr = (index("JanFebMarAprMayJunJulAugSepOctNovDec",t[2])+2)/3
    currSecs = mktime(t[3] " " monthNr " " t[1] " " t[4] " " t[5] " " t[6])

    if ( count[$2] == 1 ) {
        firstSecs[$2] = currSecs
    }
    else if ( (currSecs - firstSecs[$2]) < 15 ) {
        print $2
    }
}

$ awk -f tst.awk file
000.111.026.111
060.121.125.144

Creo que está muy claro lo que está haciendo, por lo que no es necesario agregar texto que lo explique, pero si tiene alguna pregunta, no dude en preguntar.

Ah, y mencionó en un comentario que deseaba saber una forma de convertir sus direcciones IP a valores ficticios para poder publicar un ejemplo más completo, bueno, aquí hay una forma que sería lo suficientemente buena para su problema específico:

$ awk '
    BEGIN { FS=OFS="|" }
    !($2 in map) { ip=sprintf("%012d",++cnt); gsub(/.../,"&.",ip); sub(/.$/,"",ip); map[$2]=ip }
    { $2=map[$2]; print }
' file
29/Oct/2020:07:41:42|000.000.000.001|200|/page-a/
29/Oct/2020:08:30:40|000.000.000.002|200|/page-a/
29/Oct/2020:08:30:44|000.000.000.002|200|/page-b/
29/Oct/2020:08:30:45|000.000.000.002|200|/page-c/
29/Oct/2020:08:30:47|000.000.000.002|200|/page-d/
29/Oct/2020:08:30:47|000.000.000.003|200|/page-h/
29/Oct/2020:08:30:48|000.000.000.002|200|/page-e/
29/Oct/2020:07:41:49|000.000.000.004|200|/page-a/
29/Oct/2020:08:41:52|000.000.000.005|200|/page-f/
29/Oct/2020:08:41:52|000.000.000.005|200|/page-g/
29/Oct/2020:08:41:54|000.000.000.002|200|/page-k/
29/Oct/2020:08:41:55|000.000.000.005|200|/page-l/
29/Oct/2020:08:41:57|000.000.000.005|200|/page-n/
29/Oct/2020:08:41:58|000.000.000.005|200|/page-s/

Editar: así es como podría haber comenzado a investigar la diferencia entre la salida que produce mi script y la salida que produce la versión del script de Daves que ejecutó:

$ awk -f morton-botfilter.awk.txt output3test.csv > morton.out
$ awk -f dave-botfilter.awk.txt output3test.csv > dave.out
$ ip=$(comm -13 <(sort morton.out) <(sort dave.out) | head -1)
$ grep "$ip" output3test.csv | head -5
03/Nov/2020:07:52:55|000.000.000.007|200|/page-7/
03/Nov/2020:08:05:32|000.000.000.007|200|/page-11/
03/Nov/2020:11:28:56|000.000.000.007|200|/page-77/
03/Nov/2020:13:52:32|000.000.000.007|200|/page-143/
03/Nov/2020:13:52:33|000.000.000.007|200|/page-144/

Tenga en cuenta que hay mucho más de 15 segundos entre la primera y la última marca de tiempo anterior, lo que le indica que el script en dave-botfilter.awk.txt está roto. Consulte los comentarios a continuación para obtener más información.

Ya que quieres aprender awk y aparentemente tienes ÑU awk (boquiabierto), awk -f script <logfile dónde script contiene

BEGIN{ split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",n2m);
  for(i=1;i<=12;i++) m2n[n2m[i]]=i; FS="|"; }
function fixtime(str ,tmp){ split(str,tmp,"[:/]");
  return mktime(tmp[3] OFS m2n[tmp[2]] OFS tmp[1] OFS tmp[4] OFS tmp[5] OFS tmp[6]) }
++count[$2]==1 { first[$2]=fixtime($1) }
count[$2]==5 && fixtime($1)-first[$2]<15 { print $2 }

Las dos primeras líneas configuran una matriz m2n (mes a número) que asigna Jan a 1, Feb a 2, etc. y también establece el delimitador de campo en |. (En su lugar, podría hacer m2n["Jan"]=1; m2n["Feb"]=2; etc, pero eso es más tedioso.

Las siguientes dos líneas definen una función que divide su formato de hora usando todos / y : como delimitadores (sin necesidad de traducirlos primero al espacio), convierte el nombre del mes en un número, reordena según sea necesario y alimenta a mktime() (solo boquiabierto). En lugar de OFS (que por defecto es un espacio y no se ha cambiado) puede usar literal " " pero eso me parece más feo.

La quinta y sexta líneas encuentran el primero ocurrencia de cualquier IPaddr y recuerde su marca de tiempo, y la quinto ocurrencia del mismo IPaddr y compare su marca de tiempo con la recordada para ver si el intervalo es menor a 15 segundos. Algunas personas pondrían un ;next en la acción de la quinta línea para dejar en claro que la quinta y sexta líneas de script no se ejecutarán en el mismo registro (es decir, línea de datos) pero no me molesté.

QEF.

Si lo prefiere, puede poner todo el script en la línea de comandos en '...' en lugar de usar un archivo de secuencia de comandos, pero no me gusta hacerlo para más de 100 caracteres.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : / /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *