Entfernen Sie alle doppelten Wörter mithilfe eines Shell-Skripts aus der Zeichenfolge

12

Ich habe eine Schnur wie

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

Ich möchte doppelte Wörter aus der Zeichenfolge entfernen, dann wird die Ausgabe wie folgt sein

"aaa,bbb,ccc"

Ich habe diesen Code Source ausprobiert

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

Es funktioniert gut mit demselben Wert, aber wenn ich meinen variablen Wert gebe, werden auch alle doppelten Wörter angezeigt.

Wie kann ich doppelte Werte entfernen?

AKTUALISIEREN

Meine Frage ist das Hinzufügen aller entsprechenden Werte zu einer einzelnen Zeichenfolge, wenn der Benutzer derselbe ist. Ich habe Daten wie diese ->

   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

Beim Codieren rufe ich alle unterschiedlichen Benutzer ab und verkette dann die Farbzeichenfolge erfolgreich. Damit ich Code verwende -

while read the records 

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

Wenn ich diese $ c-Variable drucke, erhalte ich die Ausgabe (für Benutzer AAA)

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

Ich möchte doppelte Farben entfernen. Dann sollte die gewünschte Ausgabe wie folgt sein

"red,black,blue,green"

Für diese gewünschte Ausgabe habe ich den obigen Code verwendet

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

Es wird jedoch die Ausgabe mit doppelten Werten angezeigt

"rot, schwarz, blau, rot, grün, rot, schwarz, blau, rot, grün", danke

Urvashi
quelle
3
Bitte klären Sie, was mit Ihrer Verwendung nicht stimmt. Ich verstehe nicht, was Sie unter "wenn ich meinen variablen Wert gebe" verstehen. Welchen Wert geben Sie? Wo scheitert es?
Terdon
echo 'aaa aaa aaa bbb bbb ccc bbb ccc' | xargs -n1 | sort -u | xargsgibt aaa bbb ccc.. also müssen Sie den genauen Code s='aaa aaa aaa bbb bbb ccc bbb ccc'; echo "$s" | xargs -n1 | sort -u | xargs
Sundeep
String-Wert kommt dynamisch. Es wird derselbe Wert gedruckt (enthält einen doppelten Wert).
Urvashi
1
Ja, zeigen Sie den Code, der fehlgeschlagen ist. Wie würden wir sonst wissen, was schief gelaufen sein könnte?
Sundeep
Ist die Bestellung wichtig?
Jacob Vlijm

Antworten:

11

Noch ein Awk, nur zum Spaß:

$ 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 

Übrigens funktioniert auch Ihre Lösung gut mit Variablen:

$ b="zebra ant spider spider ant zebra ant" 
$ echo "$b" | xargs -n1 | sort -u | xargs
ant spider zebra
George Vasiliou
quelle
Ordentlicher Ansatz. Die einzige Anpassung, die ich vornehmen musste, war die Verwendung %sanstelle von %s%s. Der Grund dafür ist, dass ich eine for-Schleife durch die Ergebnisse gemacht habe und zwei Leerzeichen bei Regex-Übereinstimmungen einige Herausforderungen verursachten.
JeremyCanfield
9

Mit tr, sortunduniq

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

oder

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

eine Zeile bekommen

Michael D.
quelle
Sie müssen hinzufügen | xargs, um die Ausgabe wieder zu einer Zeile zu verbinden
Philippos
4
Oder verwenden sort -u. Oder sogar ein awk '!u[$0]++.
Benoît
2
@ Benoît Wow, ich wusste nichts davon sort -u. Ich habe die sort | uniqganze Zeit benutzt. Die verschwendeten Tastenanschläge ...
Gardenhead
8
$ echo "zebra ant spider spider ant zebra ant"  | awk -v RS="[ \n]+" '!n[$0]++' 
zebra
ant
spider
JJoao
quelle
1
Sehr schlau!!!!
George Vasiliou
@ GeorgeVasiliou, danke [oder um die Wahrheit zu sagen, sehr faul :-)]
JJoao
2

Mit gnu sed:

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

Sie können hinzufügen ;s/ */ /g, um öffentliche Leerzeichen zu entfernen.

Funktionen wie diese: Wenn ein Wort in dieser Zeile ein zweites Mal vorkommt, entfernen Sie es und beginnen Sie von vorne, bis keine Veröffentlichung mehr gefunden wird.

Philippos
quelle
Was sind \<und \>?
Irgendwann mit dem
@someonewithpc Sie stimmen nicht mit Zeichen überein, sondern mit dem Anfang und dem Ende eines Wortes, um zu verhindern, dass Teilzeichenfolgen übereinstimmen.
Philippos
Schön, aber ist das tragbar? Sind Wörter nicht durch Leerzeichen getrennt? Scheint überflüssig zu sein, um nicht mit Leerzeichen gefolgt vom Ende eines Wortes übereinzustimmen.
Irgendwann mit dem
1
@someonewithpc Nein, es ist kein Standard, deshalb habe ich gnu sed geschrieben . Das Schöne daran ist, dass Sie die erste und die letzte Saite nicht getrennt behandeln müssen
Philippos
2
perl -lane '$,=$";print grep { ! $h{$_}++ } @F'

quelle
2

Obligatorische Awk-Lösung:

$ 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 

(Das Finale echoist für die Newline da)

ilkkachu
quelle
Plus eins für die awk! Ich habe auch eine awk-Lösung gebaut, nur zum Spaß. Es gibt eine geringfügige Möglichkeit, dass Wörter im END-Bereich in zufälliger Reihenfolge gedruckt werden, da in Array-Schlüsseln eine zufällige Art und Weise auftritt.
George Vasiliou
Ja, sie werden in einer im Wesentlichen zufälligen Reihenfolge gedruckt. Die sortLösung behält jedoch auch nicht die ursprüngliche Reihenfolge bei.
Ilkkachu
Ja, guter Punkt! Sortieren Sie Ausdrucke sogar in einer anderen Reihenfolge als der Eingabe.
George Vasiliou
1
@ilkkachu Eigentlich müssen wir nicht warten, bis die Eingabe beendet ist. Mit einer geringfügigen Änderung Ihres Codes können wir entscheiden, ob Sie drucken oder nicht. awk -vRS=" " -vORS=" " '!a[$1]++ {print $1}' ; echoDadurch bleibt die Reihenfolge erhalten.
1

Python

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

Machen Sie eine ausführbare Datei und rufen Sie dann von Bash aus auf:

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

Oder Sie könnten es als Bash-Funktion implementieren, aber die Syntax ist chaotisch.

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

Option 2

Diese Option kann bei Bedarf zu einem Einzeiler werden:

#!/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(',')))"
}
wjandrea
quelle
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
天津 神 こ と
quelle
Ich verstehe es nicht
Pierre.Vriens
1
Ihrem Code fehlt eine Erklärung. Ohne Erklärung ist es schwierig zu verfolgen, was passiert. Sie scheinen auch Annahmen über die Daten zu treffen, die falsch erscheinen (durch Leerzeichen getrennte Felder), und über die bestimmte verwendete awkImplementierung ( asorti()ist keine Standardfunktion awk).
Kusalananda
0

Verwenden der ursprünglichen Tabellendaten in der Datei mit dem Namen file:

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

Dies erzeugt

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

Die drei Schritte der Pipeline:

  1. Der sedBefehl entfernt die erste Zeile, die eine Kopfzeile ist, die wir nicht lesen möchten.
  2. Der sortBefehl gibt uns eindeutige Zeilen. Die Beispieldaten nach sehen sortaus wie

    AAA         | black
    AAA         | blue
    AAA         | green
    AAA         | red
    BBB         | blue
    BBB         | red
    CCC         | red
    
  3. Der awkBefehl verwendet diese Daten und erzeugt für jeden Benutzer im Array eine durch Kommas getrennte Zeichenfolge color(wobei der Benutzername der Schlüssel zum Array ist). Am Ende (im ENDBlock) werden alle gesammelten Daten ausgegeben.
Kusalananda
quelle
-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)
Tododo Fly
quelle
Bitte fügen Sie eine Erklärung hinzu, wie Ihr Code funktioniert und warum Sie dies und das getan haben.
Xhienne