sort (/usr/bin/sort
) ist ein Programm, mit dem Datenströme oder Dateien sortiert, zusammengeführt oder auf eine bereits vorliegende Sortierung überprüft werden können. Sortierungsschlüssel können alphabetisch oder numerisch sein und konfigurierbare Teile der Eingabe(-zeilen) in ebenfalls konfigurierbarer Reihenfolge umfassen.
Der Funktionsumfang wie auch die Funktionsweise von sort
ist für UNIX-Systeme durch den POSIX-Standard geregelt[1], dagegen weist das GNU-sort
einige Abweichungen von diesem Standard auf. Die Single UNIX Specification listet das Utility sort
als „mandatory“ (notwendigen Bestandteil) und spezifiziert sein erwartbares Verhalten.[2]
sort
[3] arbeitet zeilenorientiert, Gegenstände der Sortierung sind sogenannte Records (entspricht Zeilen), die durch Newline-Zeichen getrennt sind. Jeder solche Record besteht seinerseits aus Fields, die durch Field Separators getrennt sind. Der Default für den Field Separator ist das blank, es kann aber auch jedes andere Zeichen über die Kommandozeilen-Option -t <char>
gewählt werden.
Sortierschlüssel werden definiert, indem ein Feld (oder auch ein Teil davon, etwa das dritte bis fünfte Zeichen eines bestimmten Feldes) und die dazugehörige Sortiermethode (alphabetisch oder numerisch) angegeben wird. Komplexe Sortierungsschlüssel können aus mehreren aufeinanderfolgenden solchen Einzelschlüsseln aufgebaut werden. Zum Beispiel kann nach einem Datumsfeld im Format „TT-MM-JJJJ“ sortiert werden, indem numerisch primär nach dem 7.–11. Zeichen, als Sekundärschlüssel nach dem 4.–5. Zeichen und als Tertiärschlüssel nach dem 1.–2. Zeichen sortiert wird (die Option -n
am Anfang definiert alle nachfolgenden Schlüssel als numerisch):
sort -n -k 1.7,1.11 -k 1.4,1.5 -k 1.1,1.2 /path/to/input
Wird nichts anderes explizit angegeben, so gilt der nach der letzten Schlüsseldefinition anschließende Rest der Zeile als letzter Teilschlüssel (im Extremfall – wenn überhaupt kein Schlüssel definiert wird – bedeutet dies, dass sort
nach dem gesamten Record sortiert). Ist dies nicht gewünscht, so muss das Schlüsselende ausdrücklich angegeben werden:
sort -k 2 /path/to/input # sortiert nach Feld 2 bis Zeilenende sort -k 2,2 /path/to/input # sortiert ausschließlich nach Feld 2
Alphabetische Sortierungen werden von den Internationalisierungs-Einstellungen, insbesondere den Variablen LANG
bzw. LC_ALL
, LC_COLLATE
usw. erheblich beeinflusst, auch numerische Sortierungen reagieren in ihrem Verhalten auf den jeweiligen Wert von LC_NUMERIC
.
Wie die meisten im POSIX-Standard definierten UNIX-tools entspricht auch sort
den Utility Syntax Guidelines[1][4], allerdings mit der Ausnahme der Guideline 9. Außerdem werden sowohl -
wie auch +
als option delimiter akzeptiert.
sort
schreibt seine Ausgabe, sollte nichts anderes angegeben werden, nach stdout
und Fehlermeldungen nach stderr
. Diese Ausgaben können mit den üblichen Mitteln (Pipeline, Redirection) umgelenkt werden. Darüber hinaus steht der Switch -o <file>
zur Verfügung, der eine definierte Datei als Ziel der Standard-Ausgabe festlegt.
sort
nimmt als Eingabe entweder einen Datenstrom auf stdin
oder ein oder mehrere Dateien als Argument entgegen. Werden mehrere Dateien angegeben, so können diese im Zuge der Sortierung zu einer einzigen Ausgabedatei zusammengeführt werden. Der spezielle Dateiname -
bedeutet stdin
, sodass ein Datenstrom auch mit anderen Dateien zusammengeführt werden kann.
Neben den üblichen Rückgabewerten 0 (Erfolg) und >1 (immanente Fehlerbedingung) kann, wenn die Sortierung einer Datei lediglich überprüft wird, auch der Wert 1 zurückgegeben werden. Dieser bedeutet, dass die angegebene Datei hinsichtlich des angegebenen Kriteriums nicht sortiert ist.
Das ursprüngliche sort
kannte die heute übliche und standardisierte Form der Schlüsseldefinition über multiple -k <Teilschlüssel>
-Ausdrücke nicht. Stattdessen wurde der Schlüsselbeginn mit dem Switch +N[.M]
, das Ende des jeweiligen Teilschlüssels mit -N[.M]
angegeben, wobei N
die (null-basierte) Nummer des Feldes, M
die (ebenfalls null-basierte) Nummer des Zeichens innerhalb des Feldes darstellt. Das folgende Beispiel bietet dieselbe Schlüsseldefinition in alter und neuer Schreibweise. Es sortiert das User-Verzeichnis /etc/passwd
numerisch (-n
) nach dem 3. Feld (der User-ID), wobei „:“ als Field Separator dient (-t':'
):
sort -t':' -n +2 -3 /etc/passwd sort -t':' -n -k 3,3 /etc/passwd
Diese Methode ist in bestehenden Scripten noch sehr häufig zu sehen, dennoch wird von ihrem Gebrauch mittlerweile abgeraten. Auch wenn die meisten heutigen Implementierungen diese Schreibweise noch verstehen, so ist sie dennoch nicht mehr Bestandteil des POSIX-Standards und portable Scripte sollten sie deshalb nicht voraussetzen.
Neben der grundsätzlichen Unterscheidung in alphanumerische und numerische Sortierung und den bereits erwähnten Internationalisierungs-Variablen stehen dem Benutzer noch eine Reihe weiterer Möglichkeiten zur Verfügung, die Sortierreihenfolge zu beeinflussen. Dies kann jeweils für die gesamte Sortierung global über eine Option oder nur für einen Teilschlüssel durch einen nachgestellten Modifikator geschehen. Option und Modifikator lauten dabei jeweils gleich.
sort -n -k 3,3 -k 4,4 /path/to/input # -n gilt global für beide Schlüssel sort -k 3,3n -k 4,4 /path/to/input # -n gilt lediglich für den ersten Teilschlüssel
b
-k 2.2b,2
lässt den Sortierschlüssel etwa mit dem zweiten nicht-Blank des zweiten Feldes beginnen und mit dem letzten Zeichen des zweiten Feldes enden.d
LC_CTYPE
festlegt, was unter alphanumerisch verstanden wird.f
LC_CTYPE
legt fest, welche Zeichenpaare dabei korrespondieren.i
d
, stattdessen werden alle nicht druckbaren Zeichen ignoriert. Auch hier legt LC_CTYPE
fest, was unter „nicht druckbar“ verstanden wird.n
r
Für Verwirrung sorgt regelmäßig die unterschiedliche Behandlung führender Leerzeichen, je nachdem, ob -t
auf der Kommandozeile angegeben wird oder nicht. Insbesondere dann, wenn als Field Separator das Blank angegeben wird, was scheinbar den Default widerspiegelt. Dieser ist jedoch der Wechsel zwischen einem anderen Zeichen und einem Blank.
Wird -t
nicht angegeben, so wird der führende Field Separator dem jeweiligen Feld zugeschlagen, deshalb werden führende Blanks dem ersten Feld zugerechnet, während sie ansonsten wie andere Zeichen behandelt werden und – im Falle von -t' '
– als Field Separator fungieren. Hingegen wird bei Angabe von -t
der Field Separator nicht als Teil des Felds betrachtet. Der POSIX-Standard führt in seinen erklärenden Hinweisen folgendes Beispiel an (Blanks als <b>
repräsentiert)[1]:
sort <<EOF <b><b>foo EOF # erstes Feld: "<b><b>foo", zweites Feld leer, drittes Feld leer sort -t'<b>' <<EOF <b><b>foo EOF # erstes Feld leer, zweites Feld leer, drittes Feld "foo"