GNU/Linux >> Tutoriales Linux >  >> Linux

¿Eliminar campos duplicados en una columna determinada?

Me gustaría eliminar de una columna dada ($2 en el ejemplo) los campos duplicados (separados por comas).

Archivo de entrada:

A    1,2,3,4   
B    4,5,6,3
C    2,15

Salida esperada:

A    1,2,3,4
B    5,6
C    15

Respuesta aceptada:

perl -lpe 's/sKS+/join ",", grep {!$seen{$_}++} split ",", $&/e'

Puede ejecutar lo anterior así:

$ perl -lpe 's/sKS+/join ",", grep {!$seen{$_}++} split ",", $&/e' afile 
A    1,2,3,4
B    5,6
C    15

Cómo funciona

Primero llamando a perl con -lpe hace las siguientes 3 cosas.

  • -l[octal] habilitar el procesamiento de final de línea, especifica el terminador de línea
  • -p asumir bucle como -n pero imprimir línea también, como sed
  • -e program una línea de programa (se permiten varias -e, omitir archivo de programa)

Básicamente, esto toma el archivo, elimina las líneas nuevas, opera en una línea y luego vuelve a agregar un carácter de línea nueva cuando termina. Por lo tanto, solo se trata de recorrer el archivo y ejecutar nuestro código Perl en cada uno de ellos.

En cuanto al código Perl real:

  • s significa un carácter de espaciado (los cinco caracteres [ fnrt] y v en versiones más recientes de perl , como [[:space:]] ).
  • K Mantenga las cosas que quedan de la K, no las incluya en $&
  • S+ uno o más caracteres que no están en el conjunto [ fnrtv]

El join ",", tomará los resultados y volverá a unir cada campo para que esté separado por una coma.

La split ",", $& tomará las coincidencias encontradas por S+ y divídalos en solo los campos, sin la coma.

El grep {!$seen{$_}++} tomará el número de cada campo, lo agregará al hash, $seen{} donde el número de cada campo es $_ a medida que avanzamos por cada uno de ellos. Cada vez que se "ve" un número de campo, se cuenta a través del ++ operador, $seen{$_}++ .

El grep{!$seen{$_}++} devolverá un valor de campo si solo se ha visto una vez.

Modificado para ver lo que está pasando

Si usa esta abominación modificada, puede ver lo que sucede a medida que este trazador de líneas de Perl se mueve a través de las líneas del archivo.

$ perl -lpe 's/sKS+/join ",", grep {!$seen{$_}++} split ",", $&/e; @a=keys %seen; @b=values %seen; print "keys: @a | vals: @b"' afile 
keys: 4 1 3 2 | vals: 1 1 1 1
A    1,2,3,4
keys: 6 4 1 3 2 5 | vals: 1 2 1 2 1 1
B    5,6
keys: 6 4 1 3 2 15 5 | vals: 1 2 1 2 2 1 1
C    15

Esto te muestra el contenido de $seen{} al final del procesamiento de una línea del archivo. Tomemos la segunda línea del archivo.

B    4,5,6,3

Y así es como mi versión modificada muestra esa línea:

keys: 6 4 1 3 2 15 5 | vals: 1 2 1 2 2 1 1

Esto significa que hemos visto el campo n.° 6 (1 vez), el campo n.° 4 (2 veces), etc. y el campo n.° 5 (1 vez). Así que cuando grep{...} devuelve los resultados, solo devolverá resultados de esta matriz si estaba presente en esta línea (4,5,6,3) y si la hemos visto solo 1 vez (6,1,15,5). La intersección de estas 2 listas es (5,6) y eso es lo que devuelve grep .

Referencias

  • perlre – perldoc.perl.org
Relacionado:¿Forma de modificar un archivo en el lugar?
Linux
  1. Cómo encontrar y eliminar fotos duplicadas en Linux

  2. Eliminar una clave caducada en APT

  3. ¿Eliminar líneas basadas en duplicados dentro de una columna sin ordenar?

  4. Cómo eliminar palabras duplicadas de un archivo de texto sin formato usando el comando de Linux

  5. ¿Hay alguna manera de 'uniq' por columna?

Cómo eliminar filas duplicadas en MySQL

Cómo encontrar y eliminar archivos duplicados/no deseados en Linux usando la herramienta 'FSlint'

Comando Desvincular en Linux (Eliminar archivo)

Cómo encontrar archivos duplicados en Linux y eliminarlos

¿Cómo eliminar entradas duplicadas en el diálogo 'abrir con' de Nautilus?

¿Cómo puedo eliminar archivos duplicados en árboles de directorios separados?