Im Gegensatz zu ksh oder zsh bietet bash keine integrierte Unterstützung für das Sortieren von Arrays oder Listen beliebiger Zeichenfolgen. Es kann Globs oder die Ausgabe von aliasoder setoder sortieren typeset(obwohl die letzten 3 nicht in der Sortierreihenfolge des Benutzers enthalten sind), aber das kann hier praktisch nicht verwendet werden.
Es gibt nichts in der POSIX-Toolchest, das beliebige Listen von Zeichenfolgen leicht sortieren kann¹ ( sortsortiert Zeilen, also nur kurze (LINE_MAX ist oft kürzer als PATH_MAX) Folgen von Zeichen außer NUL und Newline, während Dateipfade nicht leere Folgen von anderen Bytes sind als 0).
Während Sie also Ihren eigenen Sortieralgorithmus in awk(mithilfe des <Zeichenfolgenvergleichsoperators) oder sogarbash (mithilfe [[ < ]]) implementieren können , ist es für beliebige Pfade bashmöglicherweise am einfachsten, auf Folgendes zurückzugreifen perl:
Mit bash4.4+könnten Sie tun:
readarray -td '' sorted_filearray < <(perl -MFile::Basename -l0 -e '
print for sort {basename($a) cmp basename($b)} @ARGV' -- "${filearray[@]}")
Das gibt eine strcmp()ähnliche Reihenfolge. Fügen Sie für eine Reihenfolge, die auf den Sortierregeln des Gebietsschemas wie in Globs oder der Ausgabe von basiert ls, ein -MlocaleArgument hinzu perl. Für numerische Sortierung (mehr wie GNU sort -gwie es unterstützt Zahlen wie +3, 1.2e-5und nicht die Tausendertrennzeichen , wenn auch nicht hexadimals), verwenden <=>statt cmp(und wieder -Mlocalefür das Dezimalzeichen des Benutzers wie für die geehrt werden sortBefehl).
Sie sind durch die maximale Größe der Argumente für einen Befehl begrenzt. Um dies zu vermeiden, können Sie die Liste der Dateien perlauf ihrem Standard anstatt über Argumente übergeben:
readarray -td '' sorted_filearray < <(
printf '%s\0' "${filearray[@]}" | perl -MFile::Basename -0le '
chomp(@files = <STDIN>);
print for sort {basename($a) cmp basename($b)} @files')
Bei älteren Versionen von bashkönnen Sie eine while IFS= read -rd ''Schleife anstelle von verwenden readarray -d ''oder perldie Liste der ordnungsgemäß zitierten Pfade ausgeben, an die Sie sie übergeben können eval "array=($(perl...))".
Mit zshkönnen Sie eine Glob-Erweiterung vortäuschen, für die Sie eine Sortierreihenfolge definieren können:
sorted_filearray=(/(e{'reply=($filearray)'}oe{'REPLY=$REPLY:t'}))
Mit reply=($filearray)erzwingen wir tatsächlich die Glob-Erweiterung (die anfangs nur war /), um die Elemente des Arrays zu sein. Dann definieren wir die Sortierreihenfolge basierend auf dem Ende des Dateinamens.
strcmp()Legen Sie für eine ähnliche Reihenfolge das Gebietsschema auf C fest. Fügen Sie für eine numerische Sortierung (ähnlich wie bei GNU sort -V, sort -ndie beim Vergleich keinen signifikanten Unterschied macht, 1.4und 1.23(in Gebietsschemas, in denen .die Dezimalstelle steht) beispielsweise) das nGlob-Qualifikationsmerkmal hinzu.
Stattdessen oe{expression}können Sie auch eine Funktion verwenden, um eine Sortierreihenfolge wie folgt zu definieren:
by_tail() REPLY=$REPLY:t
oder fortgeschrittenere wie:
by_numbers_in_tail() REPLY=${(j:,:)${(s:,:)${REPLY:t}//[^0-9]/,}}
(also a/foo2bar3.pdf(2,3 Zahlen) sortiert nach b/bar1foo3.pdf(1,3) aber vor c/baz2zzz10.pdf(2,10)) und verwendet als:
sorted_filearray=(/(e{'reply=($filearray)'}no+by_numbers_in_tail))
Natürlich können diese auf echte Globs angewendet werden, da sie in erster Linie dafür vorgesehen sind. Zum Beispiel für eine Liste von pdfDateien in einem beliebigen Verzeichnis, sortiert nach Basisname / Schwanz:
pdfs=(**/*.pdf(N.oe+by_tail))
¹ Wenn eine strcmp()sortierte Sortierung akzeptabel ist und für kurze Zeichenfolgen, können Sie die Zeichenfolgen in ihre Hex-Codierung umwandeln, awkbevor Sie sie übergeben sortund nach dem Sortieren wieder umwandeln.