Elimine las líneas duplicadas adyacentes mientras mantiene el orden

11

Tengo un archivo con una columna con nombres que se repiten varias veces cada uno. Quiero condensar cada repetición en una, mientras mantengo cualquier otra repetición del mismo nombre que no sea adyacente a otras repeticiones del mismo nombre.

Por ejemplo, quiero girar el lado izquierdo hacia el lado derecho:

Golgb1    Golgb1    
Golgb1    Akna
Golgb1    Spata20
Golgb1    Golgb1
Golgb1    Akna
Akna
Akna
Akna
Spata20
Spata20
Spata20
Golgb1
Golgb1
Golgb1
Akna
Akna
Akna

Esto es lo que he estado usando: perl -ne 'print if ++$k{$_}==1' file.txt > file2.txt Sin embargo, este método solo mantiene a un representante desde la izquierda (es decir, Golb1 y Akna no se repiten).

¿Hay alguna manera de mantener nombres únicos para cada bloque, mientras se mantienen nombres que se repiten en múltiples bloques no adyacentes?

87 años
fuente

Respuestas:

23

uniq hará esto por ti:

$ uniq inputfile
Golgb1
Akna
Spata20
Golgb1
Akna
DopeGhoti
fuente
2
wow eso fue vergonzosamente fácil! ¡Gracias!
Edad87
@ Age87 Unix es genial! Esto solo funciona porque espera que los duplicados sean adyacentes, ya (o no desee eliminar los no adyacentes). Normalmente, la recomendación es usarsort | uniq
jpaugh
1
O más sucintamente, sort -u(:
DopeGhoti
9

Awk solución:

awk '$1 != name{ print }{ name = $1 }' file.txt

La salida:

Golgb1
Akna
Spata20
Golgb1
Akna
RomanPerekhrest
fuente
6

Pruebe esto: guarde la línea anterior y compare con la línea actual

$ perl -ne 'print if $p ne $_; $p=$_' ip.txt
Golgb1
Akna
Spata20
Golgb1
Akna

También lo has etiquetado uniq, ¿lo intentaste?

$ uniq ip.txt
Golgb1
Akna
Spata20
Golgb1
Akna
Sundeep
fuente
1

Con sed se puede hacer de la siguiente manera:

sed -e '$!N;/^\(.*\)\n\1$/!P;D' input_file

Aquí tenemos en el espacio del patrón en cualquier momento 2 líneas. Cuando la comparación entre ellos falla, imprimimos el primero y lo cortamos desde el frente y regresamos y agregamos la siguiente línea al espacio del patrón. Enjuague ... repita

Al utilizar Perl en el modo slurp, tratamos todo el archivo como una cadena larga en la que se aplica la expresión regular que hace la comparación por usted.

perl -0777pe 's//$1/ while /^(.*\n)\1+/gm' input_file
Rakesh Sharma
fuente
0

Pregunta sobre la solución sed de Rakesh Sharma.

¿Qué pasa si tiene un archivo de entrada como:

-126.1 48.206
-126.106 48.21
-126.11 48.212
-126.114 48.214
-126.116 48.216
-126.118 48.216
-126.128 48.222
-126.136 48.226

Y desea que un archivo de salida sea:

-126.1 48.206
-126.106 48.21
-126.11 48.212
-126.114 48.214
-126.116 48.216
-126.128 48.222
-126.136 48.226

Tenga en cuenta lo que falta:

-126.118 48.216

Sé que el comando que quiero es similar a tu solución:

sed -e '$!N;/^\(.*\)\n\1$/!P;D' input_file

No se puede modificar de la manera correcta para imprimir ambas columnas y solo se puede ordenar de esta manera especial con los valores de la columna 2. ¿Algun consejo?

MattS
fuente
sed -e '$!N' -e '/.*\.\([0-9]*\)\n.*\.\1$/!{P;D;}' -e 's/\n.*//;s/^/\n/;D' eliminará los elementos repetidos posteriores. Nota: esto requiere GNU sed. Para el POSIXcomportamiento, necesita una ligera alteración.
Rakesh Sharma