Sie brauchen nicht wirklich so viel Code:
IFS=$'\n' sorted=($(sort <<<"${array[*]}"))
unset IFS
Unterstützt Leerzeichen in Elementen (solange es sich nicht um eine neue Zeile handelt) und funktioniert in Bash 3.x.
z.B:
$ array=("a c" b f "3 5")
$ IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
$ printf "[%s]\n" "${sorted[@]}"
[3 5]
[a c]
[b]
[f]
Hinweis: @sorontar hat darauf hingewiesen, dass Vorsicht geboten ist, wenn Elemente Platzhalter wie *
oder enthalten ?
:
Der sortierte = ($ (...)) Teil verwendet den Operator "split and glob". Sie sollten glob deaktivieren: set -f
oder set -o noglob
oder shopt -op noglob
oder ein Element des Arrays wie *
wird zu einer Liste von Dateien erweitert.
Was ist los:
Das Ergebnis ist ein Höhepunkt von sechs Dingen, die in dieser Reihenfolge geschehen:
IFS=$'\n'
"${array[*]}"
<<<
sort
sorted=($(...))
unset IFS
Zuerst die IFS=$'\n'
Dies ist ein wichtiger Teil unserer Operation, der das Ergebnis von 2 und 5 folgendermaßen beeinflusst:
Gegeben:
"${array[*]}"
Erweitert sich auf jedes Element, das durch das erste Zeichen von begrenzt ist IFS
sorted=()
Erstellt Elemente durch Aufteilen auf jedes Zeichen von IFS
IFS=$'\n'
Richtet die Dinge so ein, dass Elemente mit einer neuen Zeile als Trennzeichen erweitert und später so erstellt werden, dass jede Zeile zu einem Element wird. (dh Aufteilen in eine neue Zeile.)
Das Abgrenzen durch eine neue Zeile ist wichtig, da dies so sort
funktioniert (Sortieren pro Zeile). Das Teilen durch nur eine neue Zeile ist nicht so wichtig, muss jedoch Elemente beibehalten, die Leerzeichen oder Tabulatoren enthalten.
Der Standardwert von IFS
ist ein Leerzeichen , eine Registerkarte , gefolgt von einer neuen Zeile , und wäre für unseren Vorgang nicht geeignet.
Als nächstes das sort <<<"${array[*]}"
Teil
<<<
, hier Strings genannt , nimmt die Erweiterung von "${array[*]}"
, wie oben erläutert, und speist sie in die Standardeingabe von ein sort
.
In unserem Beispiel sort
wird folgende Zeichenfolge eingegeben:
a c
b
f
3 5
Da sort
sortiert , produziert es:
3 5
a c
b
f
Als nächstes das sorted=($(...))
Teil
Der $(...)
Teil, der als Befehlssubstitution bezeichnet wird , bewirkt, dass content ( sort <<<"${array[*]}
) wie ein normaler Befehl ausgeführt wird, während die resultierende Standardausgabe als Literal verwendet wird, das dorthin geht, wo immer es $(...)
war.
In unserem Beispiel ergibt dies etwas Ähnliches wie das einfache Schreiben:
sorted=(3 5
a c
b
f
)
sorted
wird dann zu einem Array, das durch Aufteilen dieses Literals in jede neue Zeile erstellt wird.
Endlich, das unset IFS
Dies setzt den Wert von IFS
auf den Standardwert zurück und ist nur eine gute Vorgehensweise.
Es soll sicherstellen, dass wir keine Probleme mit irgendetwas verursachen, auf das wir uns IFS
später in unserem Skript stützen. (Andernfalls müssten wir uns daran erinnern, dass wir die Dinge umgestellt haben - etwas, das für komplexe Skripte möglicherweise unpraktisch ist.)
IFS
, es wird Ihre Elemente in kleine Teile teilen, wenn sie Leerzeichen enthalten. Versuchen Sie das zB mitIFS=$'\n'
weggelassen und sehen Sie!IFS
teilt es Ihre Elemente in kleine Teile auf, wenn sie nur eine bestimmte Art von Leerzeichen enthalten. Gut; nicht perfekt :-)unset IFS
notwendig? Ich dachte, das VoranstellenIFS=
eines Befehls umfasste nur die Änderung dieses Befehls und kehrte danach automatisch zum vorherigen Wert zurück.sorted=()
es sich nicht um einen Befehl handelt, sondern um eine zweite Variablenzuweisung.