Ein bisschen hacky, aber das sollte es tun:
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Führen Sie die Array-Zuweisung aus, um die sortierten eindeutigen Ergebnisse wieder in einem Array zu speichern :
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
Wenn Ihre Shell Herestrings unterstützt ( bash
sollte), können Sie einen echo
Prozess sparen , indem Sie ihn ändern in:
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
Eingang:
ids=(aa ab aa ac aa ad)
Ausgabe:
aa ab ac ad
Erläuterung:
"${ids[@]}"
- Syntax für die Arbeit mit Shell-Arrays, unabhängig davon, ob sie als Teil echo
oder als Herestring verwendet werden. Der @
Teil bedeutet "alle Elemente im Array"
tr ' ' '\n'
- Konvertieren Sie alle Leerzeichen in Zeilenumbrüche. Weil Ihr Array von der Shell als Elemente in einer einzelnen Zeile gesehen wird, die durch Leerzeichen getrennt sind. und weil sort erwartet, dass die Eingabe in separaten Zeilen erfolgt.
sort -u
- nur eindeutige Elemente sortieren und beibehalten
tr '\n' ' '
- Konvertieren Sie die zuvor hinzugefügten Zeilenumbrüche wieder in Leerzeichen.
$(...)
- Befehlsersetzung
- Nebenbei:
tr ' ' '\n' <<< "${ids[@]}"
ist eine effizientere Methode:echo "${ids[@]}" | tr ' ' '\n'
uniq=($(printf "%s\n" "${ids[@]}" | sort -u)); echo "${uniq[@]}"
printf
diese Weise verwenden können (geben Sie mehr Argumente alssorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
. Ohne die zusätzlichen Klammern wurde es als Zeichenfolge angegeben.... | uniq | ...
anstelle von... | sort -u | ...
.uniq
entfernt nur aufeinanderfolgende Duplikate. Im Beispiel in dieser Antwortsorted_unique_ids
wird am Ende identisch mit dem Originalids
. Versuchen Sie es, um Ordnung zu erhalten... | awk '!seen[$0]++'
. Siehe auch stackoverflow.com/questions/1444406/… .Wenn Sie Bash Version 4 oder höher ausführen (was in jeder modernen Linux-Version der Fall sein sollte), können Sie eindeutige Array-Werte in bash erhalten, indem Sie ein neues assoziatives Array erstellen, das jeden der Werte des ursprünglichen Arrays enthält. Etwas wie das:
Dies funktioniert, weil in jedem Array (assoziativ oder traditionell, in jeder Sprache) jeder Schlüssel nur einmal angezeigt werden kann. Wenn die
for
Schleife den zweiten Wert vonaa
in erreichta[2]
, überschreibt sieb[aa]
den ursprünglich füra[0]
.Das Ausführen von Dingen in nativem Bash kann schneller sein als das Verwenden von Pipes und externen Tools wie z. B.
sort
unduniq
bei größeren Datensätzen werden Sie wahrscheinlich eine bessere Leistung erzielen, wenn Sie eine leistungsfähigere Sprache wie awk, python usw. verwenden.Wenn Sie sich sicher fühlen, können Sie die
for
Schleife vermeiden , indem Sie dieprintf
Möglichkeit nutzen, das Format für mehrere Argumente zu recyceln, obwohl dies anscheinend erforderlich isteval
. (Hör jetzt auf zu lesen, wenn du damit einverstanden bist.)Der Grund, den diese Lösung erfordert,
eval
besteht darin, dass Array-Werte vor der Wortteilung ermittelt werden. Dies bedeutet, dass die Ausgabe der Befehlssubstitution als einzelnes Wort und nicht als Satz von Schlüssel-Wert-Paaren betrachtet wird.Während dies eine Subshell verwendet, werden nur Bash-Buildins verwendet, um die Array-Werte zu verarbeiten. Stellen Sie sicher, dass Sie Ihre Verwendung
eval
mit kritischem Auge bewerten . Wenn Sie nicht zu 100% sicher sind, dass chepner, glenn jackman oder greycat keinen Fehler an Ihrem Code finden, verwenden Sie stattdessen die for-Schleife.quelle
Mir ist klar, dass dies bereits beantwortet wurde, aber es wurde ziemlich häufig in den Suchergebnissen angezeigt, und es könnte jemandem helfen.
Beispiel:
quelle
ids=(ab "a a" ac aa ad ac aa);IFS=$'\n' ids2=(`printf "%s\n" "${ids[@]}" |sort -u`)
, musste ichIFS=$'\n'
Folgendes tun : , also fügte ich hinzu, vorgeschlagen von @gniourf_gniourfIFS=$'\n'; ids2=(...)
da eine temporäre Zuweisung vor variablen Zuweisungen nicht möglich ist. Verwenden Sie stattdessen diese Konstruktion :IFS=$'\n' read -r -a ids2 <<<"$(printf "%s\n" "${ids[@]}" | sort -u)"
.Wenn Ihre Array-Elemente Leerzeichen oder andere Shell-Sonderzeichen haben (und können Sie sicher sein, dass dies nicht der Fall ist?), Um Ihr Array zu erfassen (und Sie sollten dies einfach immer tun), drücken Sie Ihr Array in doppelten Anführungszeichen aus! zB
"${a[@]}"
. Bash interpretiert dies wörtlich als "jedes Array-Element in einem separaten Argument ". Innerhalb von Bash funktioniert das einfach immer, immer.Um ein sortiertes (und eindeutiges) Array zu erhalten, müssen wir es in ein Format konvertieren, das die Sortierung versteht, und es wieder in Bash-Array-Elemente konvertieren können. Dies ist das Beste, was ich mir ausgedacht habe:
Leider schlägt dies im Sonderfall des leeren Arrays fehl und verwandelt das leere Array in ein Array mit 1 leeren Element (da printf 0 Argumente hatte, aber immer noch so druckt, als hätte es ein leeres Argument - siehe Erklärung). Also muss man das in einem Wenn oder so fangen.
Erläuterung: Das% q-Format für printf "shell entgeht" dem gedruckten Argument, so dass bash in so etwas wie eval wiederhergestellt werden kann! Da jedes Element in einer eigenen Zeile als Shell gedruckt wird, ist das einzige Trennzeichen zwischen den Elementen die neue Zeile. Bei der Array-Zuweisung wird jede Zeile als Element verwendet, wobei die maskierten Werte in Literaltext analysiert werden.
z.B
Die Auswertung ist erforderlich, um das Escapezeichen von jedem Wert zu entfernen, der in das Array zurückkehrt.
quelle
uniq
stattdessensort -u
.uniq
dies bei unsortierten Listen nicht ordnungsgemäß funktioniert. Daher muss es immer in Kombination mit verwendet werdensort
.'sort' kann verwendet werden, um die Ausgabe einer for-Schleife zu ordnen:
und eliminiere Duplikate mit "-u":
Schließlich können Sie Ihr Array einfach mit den eindeutigen Elementen überschreiben:
quelle
ids=( `for i in ${ids[@]}; do echo $i; done | uniq` )
Dieser wird auch die Ordnung bewahren:
und um das ursprüngliche Array mit den eindeutigen Werten zu ändern:
quelle
uniq
. Es muss sortiert werden, wo awk dies nicht tut, und die Absicht dieser Antwort ist es, die Reihenfolge beizubehalten, wenn die Eingabe unsortiert ist.Stellen Sie zum Erstellen eines neuen Arrays mit eindeutigen Werten sicher, dass Ihr Array nicht leer ist, und führen Sie einen der folgenden Schritte aus:
Doppelte Einträge entfernen (mit Sortierung)
Doppelte Einträge entfernen (ohne zu sortieren)
Warnung: Versuchen Sie nicht, so etwas zu tun
NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
. Es wird auf Leerzeichen brechen.quelle
sort -u
werden müssenuniq
.uniq
nur benachbarte doppelte Zeilen zusammen, es ist also nicht dasselbe wieawk '!x[$0]++'
.quelle
Ohne die ursprüngliche Bestellung zu verlieren:
quelle
Wenn Sie eine Lösung wünschen, die nur Bash-Interna verwendet, können Sie die Werte als Schlüssel in einem assoziativen Array festlegen und dann die Schlüssel extrahieren:
Dies wird ausgegeben
quelle
Eine weitere Option für den Umgang mit eingebetteten Leerzeichen besteht darin, sie durch Nullen zu begrenzen
printf
, zu unterscheidensort
und dann mithilfe einer Schleife wieder in ein Array zu packen:Am Ende
input
undoutput
enthalten Sie die gewünschten Werte (vorausgesetzt, die Reihenfolge ist nicht wichtig):quelle
Wie wäre es mit dieser Variante?
quelle
sorted_arr=($(printf '%s\n' "${ids[@]}" | sort -u)
.Versuchen Sie dies, um eindeutige Werte für die erste Spalte in der Datei zu erhalten
quelle
quelle