Estoy tratando de encontrar identificadores duplicados en un archivo csv grande, solo hay un registro por línea, pero la condición para encontrar un duplicado será la primera columna.<id>,<value>,<date>
ejemplo.csv
11111111,high,6/3/2019
22222222,high,6/3/2019
33333333,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Salida deseada:
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
No se requiere ningún pedido para la salida.
Respuesta1
Usando AWK:
awk -F, 'data[$1] && !output[$1] { print data[$1]; output[$1] = 1 }; output[$1]; { data[$1] = $0 }'
Esto analiza cada línea y se comporta de la siguiente manera:
- si ya hemos visto el valor en la primera columna, tenga en cuenta que debemos generar cualquier línea que coincida con ese valor y generar la línea memorizada;
- generar la línea actual si su primera columna coincide con la que queremos generar;
- almacenar la línea actual escrita en la primera columna.
Respuesta2
Si todos sus ID tienen la misma longitud (8 caracteres en su ejemplo), puede hacer todo usando sort
GNU uniq
:
$ sort file | uniq -Dw 8
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Si no tienen la misma longitud, aún puedes usar este enfoque, pero se vuelve un poco más complicado:
$ tr ',' ' ' < file | sort | rev | uniq -f2 -D | rev | tr ' ' ','
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Respuesta3
awk -F, '$1 in m { print m[$1]$0; m[$1]=""; next }
{ m[$1]=$0 "\n" }' ex
Respuesta4
Esto se puede hacer utilizando GNU sed
sus construcciones de expresiones regulares extendidas. Primero cargamos el archivo en el espacio de patrón y luego eliminamos cualquier línea que no se repita desde el comienzo del espacio de patrón. Además, \n\n
se coloca una bandera, , al final del espacio del patrón, donde colocamos las líneas repetidas. Entonces, una vez que esta bandera aparece hasta el comienzo del espacio del patrón => la operación termina y ahora podemos continuar y eliminar los marcadores del espacio del patrón e imprimir en la salida estándar.
$ sed -Ee '
$!{
N;s/^/\n/
$s/$/\n\n/;D
}
/^([^,\n]*),[^\n]*\n(.*\n)?\1,/!D
s/^([^\n]*)(.*)/\2\1\n/;/^\n\n/!D
s/^\n\n//;s/\n$//
' inp
Esta es una POSIX-sed
versión Y otra forma de abordar el problema en la que no mantenemos el archivo completo en ningún momento ni en el patrón ni en los espacios de retención. Tan pronto como se ve una línea duplicada, se imprime en la salida estándar Y la línea de referencia se marca e imprime, marcada porque no queremos imprimirla la próxima vez que se vea un duplicado.
$ sed -ne '
H;g;y/\n_/_\n/
/.*_\([^,_]*\)\(,[^_]*\)\[0]_\(.*_\)\{0,1\}\1,[^_]*$/{
s//\1\2/;y/_\n/\n_/;p
g;s/.*\n//p;g;y/\n_/_\n/
s/\(.*_\([^,_]*\),[^_]*\)\[0]\(_\(.*_\)\{0,1\}\)\2,[^_]*$/\1[1]\3/
s/_$//;y/_\n/\n_/;bh
}
/.*_\([^,_]*\)\(,[^_]*\)\[1]_\(.*_\)\{0,1\}\1,[^_]*$/{
s/.*_//;y/_\n/\n_/;p
g;s/\(.*\)\n.*/\1/;bh
}
y/_\n/\n_/;s/$/[0]/;:h;h
' inp
Esta es una Perl
solución basada en el problema en el que mantenemos las líneas en un hash de matriz. Tan pronto como vemos una línea repetida, imprimimos la matriz y también la vaciamos, y también imprimimos la línea duplicada.
$ perl -F, -lane '
push(@{$h{$F[0]}},$_),next if ! exists $h{$F[0]};
print for splice(@{$h{$F[0]}}),$_;
' inp
Producción:
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019