Rimuovi tutte le parole duplicate dalla stringa usando lo script della shell


12

Ho una stringa come

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

Voglio rimuovere la parola duplicata dalla stringa, quindi l'output sarà simile

"aaa,bbb,ccc"

Ho provato questo codice sorgente

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

Funziona bene con lo stesso valore, ma quando do il mio valore variabile, mostra anche tutte le parole duplicate.

Come posso rimuovere il valore duplicato.

AGGIORNARE

La mia domanda è aggiungere tutto il valore corrispondente in una singola stringa se l'utente è lo stesso. Ho dati come questo ->

   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

Nella codifica prendo tutti gli utenti distinti quindi concateno con successo la stringa di colore. Per questo sto usando il codice -

while read the records 

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

Quando stampo questa variabile $ c ottengo l'output (per l'utente AAA)

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

Voglio rimuovere il colore duplicato. Quindi l'output desiderato dovrebbe essere simile

"red,black,blue,green"

Per questo output desiderato ho usato il codice sopra

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

ma visualizza l'output con valori duplicati. Come

"rosso, nero, blu, rosso, verde, rosso, nero, blu, rosso, verde" Grazie


3
Si prega di chiarire cosa c'è di sbagliato in ciò che si sta utilizzando. Non capisco cosa intendi per "quando do il mio valore variabile". Che valore dai? Dove fallisce?
terdon

echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsaaa bbb ccc.. quindi devi mostrare il codice esatto che sei stanco e l'output che hai .. con la stringa in variabile:s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep

il valore della stringa viene fornito in modo dinamico. Sta stampando lo stesso valore (contiene un valore duplicato).
Urvashi,

1
sì, mostra il codice che non ha funzionato, altrimenti come potremmo sapere cosa sarebbe potuto andare storto?
Sundeep

L'ordine è importante?
Jacob Vlijm,

Risposte:


12

Un altro awk, solo per divertimento:

$ 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 

A proposito, anche la tua soluzione funziona bene con le variabili:

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

Approccio pulito. L'unica modifica che ho dovuto apportare è stata %sinvece di utilizzare %s%s. Il motivo è che stavo facendo un ciclo for attraverso i risultati e due spazi bianchi hanno causato alcune sfide con le partite regex.
JeremyCanfield

9

Con tr, sorteuniq

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 

per ottenere una riga


È necessario aggiungere | xargsper unire nuovamente l'output a una riga
Philippos

4
Oppure usa sort -u. O anche a awk '!u[$0]++.
Benoît

2
@ Benoît Wow, non lo sapevo sort -u. Ho usato sort | uniqtutto questo tempo.
Tasti

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

1
Molto intelligente!!!!
George Vasiliou,

@GeorgeVasiliou, grazie [o a dire la verità, molto pigro :-)]
JJoao

2

Con gnu sed:

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

È possibile aggiungere ;s/ */ /gper rimuovere spazi pubblici.

Funziona in questo modo: se una parola è una seconda volta in questa riga, rimuoverla e ricominciare fino a quando non viene più trovata alcuna pubblicazione.


Cosa sono \<e \>?
qualcuno con il

@someonewithpc Non corrispondono a nessun carattere, ma all'inizio e alla fine di una parola per impedire la corrispondenza delle sottostringhe.
Philippos,

Bello, ma è portatile? Inoltre, le parole non sono separate da spazi bianchi? Sembra ridondante per non corrispondere agli spazi bianchi seguito dalla fine di una parola.
qualcuno con il

1
@someonewithpc No, non è standard, ecco perché ho scritto gnu sed . La parte bella è che non devi gestire la prima e l'ultima stringa separatamente
Philippos,

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

2

Soluzione awk obbligatoria:

$ 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 finale echoè lì per la newline)


Più uno per il awk! Stavo costruendo anche una soluzione awk solo per divertimento. Esiste una leggera possibilità che le parole vengano stampate in ordine casuale nella sezione END a causa del modo casuale che Awk scorre nelle chiavi dell'array.
George Vasiliou,

Sì, verranno stampati in un ordine essenzialmente casuale. Tuttavia, la sortsoluzione non mantiene l'ordine originale.
ilkkachu,

Sì, buon punto! Ordinamento anche delle stampe in ordine diverso rispetto all'input.
George Vasiliou,

1
@ilkkachu In realtà non è necessario attendere la fine dell'input. Possiamo prendere la decisione di stampare o non stampare con una leggera modifica al tuo codice: awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoquesto preserva l'ordine.

1

Pitone

opzione 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)

Rendi eseguibile, quindi chiama da Bash:

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

Oppure potresti implementarlo come una funzione Bash, ma la sintassi è disordinata.

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

opzione 2

Questa opzione può diventare un liner se necessario:

#!/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

In 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

Non capisco
Pierre.Vriens,

1
Il tuo codice manca di spiegazione. Senza alcuna spiegazione, è difficile seguire ciò che sta accadendo. Sembra anche che tu faccia ipotesi sui dati che sembrano sbagliati (campi delimitati da spazi bianchi) e sulla particolare awkimplementazione utilizzata ( asorti()non è una awkfunzione standard ).
Kusalananda

0

Utilizzando i dati tabulari originali nel file chiamato file:

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

Questo genera

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

I tre passaggi della pipeline:

  1. Il sedcomando rimuove la prima riga che è un'intestazione che non vogliamo leggere.
  2. Il sortcomando ci dà linee uniche. I dati di esempio dopo l' sortaspetto

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
  3. Il awkcomando prende questi dati e produce una stringa delimitata da virgole per ogni utente dell'array color(dove il nome utente è la chiave dell'array). Alla fine (nel ENDblocco), vengono emessi tutti i dati raccolti.

-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)

Aggiungi una spiegazione su come funziona il tuo codice e perché hai fatto questo e quello.
Xhienne,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.