Elimine todas las palabras duplicadas de la cadena usando el script de shell


12

Tengo una cuerda como

"aaa,aaa,aaa,bbb,bbb,ccc,bbb,ccc"

Quiero eliminar la palabra duplicada de la cadena y luego la salida será como

"aaa,bbb,ccc"

Intenté este código Fuente

$ echo "zebra ant spider spider ant zebra ant" | xargs -n1 | sort -u | xargs

Está funcionando bien con el mismo valor, pero cuando doy mi valor variable, también muestra todas las palabras duplicadas.

¿Cómo puedo eliminar el valor duplicado?

ACTUALIZAR

Mi pregunta es agregar todo el valor correspondiente en una sola cadena si el usuario es el mismo. Tengo datos como este ->

   user name    | colour
    AAA         | red
    AAA         | black
    BBB         | red
    BBB         | blue
    AAA         | blue
    AAA         | red
    CCC         | red
    CCC         | red
    AAA         | green
    AAA         | red
    AAA         | black
    BBB         | red
    BBB         | blue
    AAA         | blue
    AAA         | red
    CCC         | red
    CCC         | red
    AAA         | green

En la codificación, busco a todos los usuarios distintos y luego concateno la cadena de color con éxito. Para eso estoy usando código:

while read the records 

    if [ "$c" == "" ]; then  #$c I defined global
        c="$colour1"
    else
        c="$c,$colour1" 
    fi

Cuando imprimo esta variable $ c obtengo el resultado (para el usuario AAA)

"red,black,blue,red,green,red,black,blue,red,green,"

Quiero eliminar el color duplicado. Entonces la salida deseada debería ser como

"red,black,blue,green"

Para esta salida deseada, utilicé el código anterior

 echo "zebra ant spider spider ant zebra ant" | xargs -n1 | sort -u | xargs

pero muestra la salida con valores duplicados.

"rojo, negro, azul, rojo, verde, rojo, negro, azul, rojo, verde" Gracias


3
Por favor, aclare qué está mal con lo que está utilizando. No entiendo lo que quieres decir con "cuando doy mi valor variable". ¿Qué valor le das? ¿Dónde falla?
terdon

echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsda aaa bbb ccc... por lo que necesita mostrar el código exacto que cansó y la salida que obtuvo ... con la cadena en variable:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

El valor de la cadena viene dinámicamente. Está imprimiendo el mismo valor (contiene un valor duplicado).
Urvashi

1
sí, muestra el código que falló, de lo contrario, ¿cómo podríamos saber qué pudo haber salido mal?
Sundeep

¿Importa el orden?
Jacob Vlijm el

Respuestas:


12

Un awk más, solo por diversión:

$ a="aaa bbb aaa bbb ccc aaa ddd bbb ccc"
$ echo "$a" | awk '{for (i=1;i<=NF;i++) if (!a[$i]++) printf("%s%s",$i,FS)}{printf("\n")}'
aaa bbb ccc ddd 

Por cierto, incluso su solución funciona bien con variables:

$ b="zebra ant spider spider ant zebra ant" 
$ echo "$b" | xargs -n1 | sort -u | xargs
ant spider zebra

Enfoque aseado. El único ajuste que tuve que hacer fue usar en %slugar de %s%s. La razón es que estaba haciendo un ciclo for a través de los resultados y dos espacios en blanco causaron algunos desafíos con las coincidencias de expresiones regulares.
JeremyCanfield

9

Con tr, sortyuniq

echo "zebra ant spider spider ant zebra ant" | tr ' ' '\n' | sort | uniq

o

echo "zebra ant spider spider ant zebra ant" | tr ' ' '\n' | sort | uniq | xargs 

para obtener una línea


Debe agregar | xargspara unir la salida a una línea nuevamente
Philippos

44
O utilice sort -u. O incluso a awk '!u[$0]++.
Benoît

2
@ Benoît Wow, no lo sabía sort -u. He estado usando sort | uniqtodo este tiempo. Las pulsaciones de teclado desperdiciadas ...
gardenhead

8
$ echo "zebra ant spider spider ant zebra ant"  | awk -v RS="[ \n]+" '!n[$0]++' 
zebra
ant
spider

1
¡¡¡¡Muy inteligente!!!!
George Vasiliou

@GeorgeVasiliou, gracias [o para decir la verdad, muy vago :-)]
JJoao

2

Con gnu sed:

sed ':s;s/\(\<\S*\>\)\(.*\)\<\1\>/\1\2/g;ts'

Puede agregar ;s/ */ /gpara eliminar espacios duplicados.

Funciones como esta: si una palabra es la segunda vez en esta línea, elimínela y comience de nuevo hasta que ya no se encuentre la duplicación.


¿Qué son \<y \>?
someonewithpc

@someonewithpc No coinciden con ningún carácter, sino con el principio y el final de una palabra para evitar que las subcadenas coincidan.
Philippos

Bien, pero ¿eso es portátil? Además, ¿no están las palabras separadas por espacios en blanco? Parece redundante para que no coincida con espacios en blanco seguidos del final de una palabra.
someonewithpc

1
@someonewithpc No, no es estándar, por eso escribí gnu sed . Lo bueno es que no tienes que manejar la primera y la última cadena por separado
Philippos

2
perl -lane '$,=$";print grep { ! $h{$_}++ } @F'

2

Solución awk obligatoria:

$ echo "ant zebra ant spider spider ant zebra ant" | 
   awk -vRS=" " -vORS=" " '!a[$1] {a[$1]++} END{ for (x in a) print x;  } ' ; echo
zebra ant spider 

(La final echoestá ahí para la nueva línea)


¡Más uno para el awk! También estaba creando una solución awk solo por diversión. Hay una pequeña posibilidad de que las palabras se impriman en orden aleatorio en la sección END debido a la forma aleatoria que itera en las teclas de matriz.
George Vasiliou

Sí, se imprimirán en un orden esencialmente aleatorio. Sin sortembargo, la solución tampoco mantiene el orden original.
ilkkachu

Si, buen punto! Incluso clasifique las impresiones en un orden diferente al de entrada.
George Vasiliou

1
@ilkkachu En realidad no necesitamos esperar a que termine la entrada. Podemos tomar la decisión de imprimir o no imprimir con una ligera modificación a su código: awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoesto preserva el pedido.

1

Pitón

Opción 1

#!/usr/bin/env python
# get_unique_words.py

import sys

l = []
for w in sys.argv[1].split(','):
  if w not in l:
    l += [ w ]
print ','.join(l)

Haga ejecutable, luego llame desde Bash:

$ ./get_unique_words.py "aaa,aaa,aaa,bbb,bbb,ccc,bbb,ccc"
aaa,bbb,ccc

O podría implementarlo como una función Bash, pero la sintaxis es desordenada.

get_unique_words(){
  python -c "
l = []
for w in '$1'.split(','):
  if w not in l:
    l += [ w ]
print ','.join(l)"
}

opcion 2

Esta opción puede convertirse en una línea si es necesario:

#!/usr/bin/env python
# get_unique_words.py

import sys

s_in = sys.argv[1]
l_in = s_in.split(',') # Turn string into a list.
set_out = set(l_in) # Turning a list into a set removes duplicates items.
s_out = ','.join(set_out) 
print s_out

En Bash:

get_unique_words(){
  python -c "print ','.join(set('$1'.split(',')))"
}

0
cat filename | awk '{ delete a; for (i=1; i<=NF; i++) a[$i]++; n=asorti(a, b); for (i=1; i<=n; i++) printf b[i]" "; print "" }' > newfile

No lo entiendo
Pierre.Vriens

1
Tu código carece de explicación. Sin explicación, es difícil seguir lo que está sucediendo. También parece hacer suposiciones sobre los datos que parecen incorrectos (campos delimitados por espacios en blanco) y sobre la awkimplementación particular que se está utilizando ( asorti()no es una awkfunción estándar ).
Kusalananda

0

Usando los datos tabulares originales en el archivo llamado file:

sed '1d' file | sort -u |
awk '{ color[$1] = ( color[$1] == "" ? $3 : color[$1] "," $3 ) }
     END { for (user in color) print user, color[user] }'

Esto genera

CCC red
BBB blue,red
AAA black,blue,green,red

Los tres pasos de la tubería:

  1. El sedcomando elimina la primera línea, que es un encabezado que no queremos leer.
  2. El sortcomando nos da líneas únicas. Los datos de muestra después del sortaspecto

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
  3. El awkcomando toma estos datos y produce una cadena delimitada por comas para cada usuario en la matriz color(donde el nombre de usuario es la clave de la matriz). Al final (en el ENDbloque), se envían todos los datos recopilados.

-2
a="aaa aaa aaa bbb bbb ccc bbb ccc"
for item in $a
do
   echo $item
done | sort -u | (while read i; do ans="$ans $i"; done ; echo $ans)

Agregue una explicación sobre cómo funciona su código y por qué hizo esto y aquello.
xhienne
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.