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


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

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


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

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.


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'

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)


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(',')))"
}

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

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.

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

Bitte fügen Sie eine Erklärung hinzu, wie Ihr Code funktioniert und warum Sie dies und das getan haben.
Xhienne
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.