it-swarm.com.de

So sortieren Sie ein Array in Bash

Ich habe ein Array in Bash, zum Beispiel:

array=(a c b f 3 5)

Ich muss das Array sortieren. Der Inhalt wird nicht nur sortiert angezeigt, sondern es wird ein neues Array mit den sortierten Elementen angezeigt. Das neue sortierte Array kann ein völlig neues oder das alte sein.

112
B3y0nd3r

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 funktionieren 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 _?_:

Der sortierte Teil = ($ (...)) verwendet den Operator "split and glob". Sie sollten glob ausschalten: _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 sind sechs Dinge, die in dieser Reihenfolge geschehen:

  1. _IFS=$'\n'_
  2. _"${array[*]}"_
  3. _<<<_
  4. sortname__
  5. sorted=($(...))
  6. _unset IFS_

Erstens, der _IFS=$'\n'_

Dies ist ein wichtiger Teil unserer Operation, der das Ergebnis von 2 und 5 folgendermaßen beeinflusst:

Gegeben:

  • _"${array[*]}"_ wird auf jedes Element erweitert, das durch das erste Zeichen von IFSbegrenzt wird.
  • sorted=() erstellt Elemente, indem auf jedes Zeichen von IFSaufgeteilt wird

_IFS=$'\n'_ richtet die Dinge ein so, dass Elemente mit einer neuen Zeile als Trennzeichen erweitert und später so erstellt werden, dass jede Zeile zu einer wird Element. (d. h. Aufteilen auf eine neue Zeile.)

Das Abgrenzen durch eine neue Zeile ist wichtig, da sortso funktioniert (Sortierung pro Zeile). Das Aufteilen einer neuen Zeile durch nur ist nicht so wichtig, wird jedoch benötigt, um Elemente zu erhalten, die Leerzeichen oder Tabulatoren enthalten.

Der Standardwert von IFSist ein Leerzeichen , ein Tabulator , gefolgt von einer neuen Zeile und würde für unseren Betrieb ungeeignet sein.

Als nächstes der Teil _sort <<<"${array[*]}"_

_<<<_, genannt here strings , übernimmt die oben erläuterte Erweiterung von _"${array[*]}"_ und fügt sie in die Standardeingabe von sortein. .

In unserem Beispiel wird sortdie folgende Zeichenfolge zugeführt:

_a c
b
f
3 5
_

Da sort nach sortiert ist, erzeugt es:

_3 5
a c
b
f
_

Als nächstes der Teil sorted=($(...))

Der Teil $(...) mit dem Namen command substitution bewirkt, dass sein Inhalt (_sort <<<"${array[*]}_) als normaler Befehl ausgeführt wird, während der resultierende Befehl verwendet wird ) Standardausgabe als das Literal, das dahin geht, wo immer $(...) war.

In unserem Beispiel sieht das so aus, als würde man einfach schreiben:

_sorted=(3 5
a c
b
f
)
_

sortedwird dann zu einem Array, das erstellt wird, indem dieses Literal in jede neue Zeile aufgeteilt wird.

Zum Schluss der _unset IFS_

Dies setzt den Wert von IFSauf den Standardwert zurück und ist nur eine gute Übung.

Es soll sicherstellen, dass wir keine Probleme mit etwas verursachen, das später in unserem Skript auf IFSbasiert. (Andernfalls müssen wir uns daran erinnern, dass wir die Dinge vertauscht haben - etwas, das für komplexe Skripte unpraktisch sein könnte.)

171
antak

Ursprüngliche Antwort:

array=(a c b "f f" 3 5)
readarray -t sorted < <(for a in "${array[@]}"; do echo "$a"; done | sort)

ausgabe:

$ for a in "${sorted[@]}"; do echo "$a"; done
3
5
a
b
c
f f

Hinweis Diese Version verarbeitet Werte, die Sonderzeichen oder Leerzeichen enthalten (außer newlines).

Hinweis readarray wird in bash 4+ unterstützt. 


Bearbeiten Basierend auf dem Vorschlag von @Dimitre hatte ich ihn folgendermaßen aktualisiert:

readarray -t sorted < <(printf '%s\0' "${array[@]}" | sort -z | xargs -0n1)

dies hat den Vorteil, dass sorting -Elemente mit korrekt eingebetteten Zeilenumbrüchen sogar verstanden werden. Wie von @ruakh korrekt signalisiert, bedeutet dies leider nicht, dass readarray das Ergebnis correct sein würde, da readarray keine Option zur Verwendung von NUL anstelle von regulären newlines als Zeilentrennzeichen hat.

33
sehe

Hier ist eine reine Bash-Quicksort-Implementierung:

#!/bin/bash

# quicksorts positional arguments
# return is in array qsort_ret
qsort() {
   local pivot i smaller=() larger=()
   qsort_ret=()
   (($#==0)) && return 0
   pivot=$1
   shift
   for i; do
      if [[ $i < $pivot ]]; then
         smaller+=( "$i" )
      else
         larger+=( "$i" )
      fi
   done
   qsort "${smaller[@]}"
   smaller=( "${qsort_ret[@]}" )
   qsort "${larger[@]}"
   larger=( "${qsort_ret[@]}" )
   qsort_ret=( "${smaller[@]}" "$pivot" "${larger[@]}" )
}

Verwendung als z.B.

$ array=(a c b f 3 5)
$ qsort "${array[@]}"
$ declare -p qsort_ret
declare -a qsort_ret='([0]="3" [1]="5" [2]="a" [3]="b" [4]="c" [5]="f")'

Diese Implementierung ist rekursiv… also hier ein iterativer Quicksort:

#!/bin/bash

# quicksorts positional arguments
# return is in array qsort_ret
# Note: iterative, NOT recursive! :)
qsort() {
   (($#==0)) && return 0
   local stack=( 0 $(($#-1)) ) beg end i pivot smaller larger
   qsort_ret=("[email protected]")
   while ((${#stack[@]})); do
      beg=${stack[0]}
      end=${stack[1]}
      stack=( "${stack[@]:2}" )
      smaller=() larger=()
      pivot=${qsort_ret[beg]}
      for ((i=beg+1;i<=end;++i)); do
         if [[ "${qsort_ret[i]}" < "$pivot" ]]; then
            smaller+=( "${qsort_ret[i]}" )
         else
            larger+=( "${qsort_ret[i]}" )
         fi
      done
      qsort_ret=( "${qsort_ret[@]:0:beg}" "${smaller[@]}" "$pivot" "${larger[@]}" "${qsort_ret[@]:end+1}" )
      if ((${#smaller[@]}>=2)); then stack+=( "$beg" "$((beg+${#smaller[@]}-1))" ); fi
      if ((${#larger[@]}>=2)); then stack+=( "$((end-${#larger[@]}+1))" "$end" ); fi
   done
}

In beiden Fällen können Sie die Reihenfolge ändern, die Sie verwenden: Ich habe Zeichenfolgenvergleiche verwendet, aber Sie können arithmetische Vergleiche verwenden, die Änderungszeit der Datei vergleichen und einfach den entsprechenden Test verwenden. Sie können es sogar generischer gestalten und ein erstes Argument verwenden, das von der Testfunktion verwendet wird, z.

#!/bin/bash

# quicksorts positional arguments
# return is in array qsort_ret
# Note: iterative, NOT recursive! :)
# First argument is a function name that takes two arguments and compares them
qsort() {
   (($#<=1)) && return 0
   local compare_fun=$1
   shift
   local stack=( 0 $(($#-1)) ) beg end i pivot smaller larger
   qsort_ret=("[email protected]")
   while ((${#stack[@]})); do
      beg=${stack[0]}
      end=${stack[1]}
      stack=( "${stack[@]:2}" )
      smaller=() larger=()
      pivot=${qsort_ret[beg]}
      for ((i=beg+1;i<=end;++i)); do
         if "$compare_fun" "${qsort_ret[i]}" "$pivot"; then
            smaller+=( "${qsort_ret[i]}" )
         else
            larger+=( "${qsort_ret[i]}" )
         fi
      done
      qsort_ret=( "${qsort_ret[@]:0:beg}" "${smaller[@]}" "$pivot" "${larger[@]}" "${qsort_ret[@]:end+1}" )
      if ((${#smaller[@]}>=2)); then stack+=( "$beg" "$((beg+${#smaller[@]}-1))" ); fi
      if ((${#larger[@]}>=2)); then stack+=( "$((end-${#larger[@]}+1))" "$end" ); fi
   done
}

Dann können Sie diese Vergleichsfunktion haben:

compare_mtime() { [[ $1 -nt $2 ]]; }

und verwenden:

$ qsort compare_mtime *
$ declare -p qsort_ret

damit die Dateien im aktuellen Ordner nach Änderungszeit sortiert werden (neueste zuerst).

HINWEIS. Diese Funktionen sind pure Bash! Keine externen Dienstprogramme und keine Subshells! Sie sind sicher für alle lustigen Symbole (Leerzeichen, Zeilenumbrüche, Glob-Zeichen usw.).

32
gniourf_gniourf

Wenn Sie keine besonderen Shell-Zeichen in den Array-Elementen behandeln müssen:

array=(a c b f 3 5)
sorted=($(printf '%s\n' "${array[@]}"|sort))

Mit bash benötigen Sie sowieso ein externes Sortierprogramm.

Mit zsh werden keine externen Programme benötigt und spezielle Shell-Zeichen sind leicht zu handhaben:

% array=('a a' c b f 3 5); printf '%s\n' "${(o)array[@]}" 
3
5
a a
b
c
f

ksh hat set -s zum Sortieren von ASCIIbetically .

26

Bei der 3-stündigen Zugfahrt von München nach Frankfurt (die ich wegen des morgigen Oktoberfestbeginns nur schwer erreichen konnte) habe ich an meinen ersten Beitrag gedacht. Die Verwendung eines globalen Arrays ist eine viel bessere Idee für eine allgemeine Sortierfunktion. Die folgende Funktion behandelt beliebige Zeichenfolgen (Zeilenumbrüche, Leerzeichen usw.):

declare BSORT=()
function bubble_sort()
{   #
    # @param [ARGUMENTS]...
    #
    # Sort all positional arguments and store them in global array BSORT.
    # Without arguments sort this array. Return the number of iterations made.
    #
    # Bubble sorting lets the heaviest element sink to the bottom.
    #
    (($# > 0)) && BSORT=("[email protected]")
    local j=0 ubound=$((${#BSORT[*]} - 1))
    while ((ubound > 0))
    do
        local i=0
        while ((i < ubound))
        do
            if [ "${BSORT[$i]}" \> "${BSORT[$((i + 1))]}" ]
            then
                local t="${BSORT[$i]}"
                BSORT[$i]="${BSORT[$((i + 1))]}"
                BSORT[$((i + 1))]="$t"
            fi
            ((++i))
        done
        ((++j))
        ((--ubound))
    done
    echo $j
}

bubble_sort a c b 'z y' 3 5
echo ${BSORT[@]}

Dies druckt:

3 5 a b c z y

Die gleiche Ausgabe wird von erstellt

BSORT=(a c b 'z y' 3 5) 
bubble_sort
echo ${BSORT[@]}

Beachten Sie, dass Bash wahrscheinlich intern Smart-Pointer verwendet, so dass die Swap-Operation könnte billig sein (obwohl ich es bezweifle). bubble_sort zeigt jedoch, dass erweiterte Funktionen wie merge_sort auch in der Shell-Sprache verfügbar sind.

8

tl; dr :

Sortieren Sie das Array a_in Und speichern Sie das Ergebnis in a_out (Elemente dürfen nicht eingebettet ​​Zeilenumbrüche enthalten[1] ):

Bash v4 +:

readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)

Bash v3:

IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)

Vorteile gegenüber Antaks Lösung :

  • Sie müssen sich keine Gedanken über versehentliches Globbing machen (versehentliche Interpretation der Array-Elemente als Dateinamenmuster), daher ist kein zusätzlicher Befehl erforderlich, um das Globbing zu deaktivieren (set -f Und set +f, Um es später wiederherzustellen).

  • Sie müssen sich keine Gedanken machen, IFS mit unset IFS Zurückzusetzen.[2]


Optionale Lesung: Erklärung und Beispielcode

Das Obige kombiniert Bash-Code mit einem externen Dienstprogramm sort für eine Lösung, die mit beliebigen - single - Linienelemente und entweder lexikalische oder numerische Sortierung (optional nach Feld) :

  • Leistung : Für ungefähr 20 Elemente oder mehr ist dies schneller als eine reine Bash-Lösung - deutlich und zunehmend, sobald Sie mehr als 100 Elemente haben.
    (Die genauen Schwellenwerte hängen von Ihrer spezifischen Eingabe, Maschine und Plattform ab.)

    • Der Grund, warum es schnell ist, ist, dass es Bash-Schleifen vermeidet.
  • printf '%s\n' "${a_in[@]}" | sort führt die Sortierung durch (standardmäßig lexikalisch - siehe sort s POSIX-Spezifikation =):

    • "${a_in[@]}" Erweitert sich sicher zu den Elementen des Arrays a_in Als einzelne Argumente, unabhängig davon, was sie enthalten (einschließlich Leerzeichen).

    • printf '%s\n' Gibt dann jedes Argument - d. H. Jedes Array-Element - unverändert in einer eigenen Zeile aus.

  • Beachten Sie die Verwendung von Prozessersetzung (<(...)), um die sortierte Ausgabe als Eingabe für read/readarray (per Weiterleitung nach stdin, <), Weil read/readarray muss Führen Sie in der current ​​Shell aus (darf nicht in einer subshell ausgeführt werden), damit die Ausgabevariable a_out sichtbar wird auf die aktuelle Shell (damit die Variable im Rest des Skripts definiert bleibt).

  • Lesen der Ausgabe von sort in eine Array-Variable:

    • Bash v4 +: readarray -t a_out Liest die einzelnen von sort ausgegebenen Zeilen in die Elemente der Array-Variablen a_out, Ohne das nachfolgende \n In jedem Element (-t).

    • Bash v3: readarray existiert nicht, daher muss read verwendet werden:
      IFS=$'\n' read -d '' -r -a a_out Weist read an, in die Array-Variable -aa_out Einzulesen und die gesamte Eingabe zeilenübergreifend (-d ''), aber das Aufteilen in Array-Elemente durch Zeilenumbrüche (IFS=$'\n'. $'\n', das einen wörtlichen Zeilenumbruch (LF) erzeugt, ist ein sogenannter ANSI C-quotierter String ).
      (-r, Eine Option, die praktisch immer für read verwendet werden sollte, deaktiviert die unerwartete Verarbeitung von \ - Zeichen.)

Kommentierter Beispielcode:

#!/usr/bin/env bash

# Define input array `a_in`:
# Note the element with embedded whitespace ('a c')and the element that looks like
# a glob ('*'), chosen to demonstrate that elements with line-internal whitespace
# and glob-like contents are correctly preserved.
a_in=( 'a c' b f 5 '*' 10 )

# Sort and store output in array `a_out`
# Saving back into `a_in` is also an option.
IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)
# Bash 4.x: use the simpler `readarray -t`:
# readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)

# Print sorted output array, line by line:
printf '%s\n' "${a_out[@]}"

Aufgrund der Verwendung von sort ohne Optionen ergibt dies lexikalisch Sortieren (Ziffern werden vor Buchstaben sortiert und Ziffernfolgen werden lexikalisch behandelt, nicht als Zahlen):

*
10
5
a c
b
f

Wenn Sie numerisch nach dem 1. Feld sortieren möchten, würden Sie sort -k1,1n Anstelle von nur sort verwenden, was ergibt (Nicht-Zahlen-Sortierung vor Zahlen und Zahlen-Sortierung) korrekt):

*
a c
b
f
5
10

[1] Verwenden Sie zum Behandeln von Elementen mit eingebetteten Zeilenumbrüchen die folgende Variante (Bash v4 + mit GNU sort):
readarray -d '' -t a_out < <(printf '%s\0' "${a_in[@]}" | sort -z).
Michał Górnys hilfreiche Antwort hat eine Bash v3-Lösung.

[2] Während IFSist ​​in der Bash v3-Variante eingestellt ist, ist die Änderung für den Befehl bestimmt.
Im Gegensatz dazu ist das, was in Antaks Antwort auf IFS=$'\n'  Folgt, eine Zuweisung und kein Befehl. In diesem Fall ist die IFS -Änderung global.

7
mklement0

Eine andere Lösung, die externe sort verwendet und mit any Sonderzeichen (außer NULs :)) zurechtkommt. Sollte mit bash-3.2 und GNU oder BSD sort arbeiten (leider enthält POSIX -z nicht).

local e new_array=()
while IFS= read -r -d '' e; do
    new_array+=( "${e}" )
done < <(printf "%s\0" "${array[@]}" | LC_ALL=C sort -z)

Sehen Sie sich zuerst die Eingabeumleitung an. Wir verwenden printf eingebaut, um die Array-Elemente mit nullterminierter Schreibweise auszugeben. Durch die Anführungszeichen wird sichergestellt, dass die Array-Elemente unverändert übergeben werden. Aufgrund der Besonderheiten von Shell printf wird der letzte Teil der Formatzeichenfolge für jeden verbleibenden Parameter erneut verwendet. Das heißt, es entspricht so etwas wie:

for e in "${array[@]}"; do
    printf "%s\0" "${e}"
done

Die nullterminierte Elementliste wird dann an sort übergeben. Mit der -z-Option werden nullterminierte Elemente gelesen, sortiert und nullterminiert ausgegeben. Wenn Sie nur die eindeutigen Elemente benötigen, können Sie -u übergeben, da es portabler ist als uniq -z. Der LC_ALL=C gewährleistet eine stabile Sortierreihenfolge unabhängig vom Gebietsschema - manchmal nützlich für Skripts. Wenn Sie möchten, dass die sort das Gebietsschema berücksichtigt, entfernen Sie das.

Das <()-Konstrukt erhält den zu lesenden Deskriptor aus der erzeugten Pipeline, und < leitet die Standardeingabe der while-Schleife auf diese um. Wenn Sie auf die Standardeingabe in der Pipe zugreifen müssen, können Sie eine andere Beschreibung verwenden - Übung für den Leser :).

Nun zurück zum Anfang. Die integrierte Variable read liest die Ausgabe des umgeleiteten Standardeintrags. Die Einstellung leer IFS deaktiviert die Word-Aufteilung, die hier nicht erforderlich ist. Daher liest read die gesamte 'Zeile' der Eingabe in die einzelne bereitgestellte Variable. Die Option -r deaktiviert auch die hier unerwünschte Escape-Verarbeitung. Schließlich setzt -d '' den Zeilentrenner auf NUL - das heißt, read soll nullterminierte Zeichenfolgen lesen.

Folglich wird die Schleife einmal für jedes nachfolgende nullterminierte Arrayelement ausgeführt, wobei der Wert in e gespeichert wird. Im Beispiel werden die Elemente nur in ein anderes Array eingefügt, Sie können sie jedoch direkt verarbeiten :).

Natürlich ist dies nur eine der vielen Möglichkeiten, um dasselbe Ziel zu erreichen. So wie ich es sehe, ist es einfacher als ein kompletter Sortieralgorithmus in bash zu implementieren, und in manchen Fällen wird es schneller sein. Es behandelt alle Sonderzeichen, einschließlich Zeilenumbrüche, und sollte auf den meisten gängigen Systemen funktionieren. Am wichtigsten ist, dass es Ihnen vielleicht etwas Neues und Geniales über bash :) beibringt.

5
Michał Górny

versuche dies:

echo ${array[@]} | awk 'BEGIN{RS=" ";} {print $1}' | sort

Ausgabe wird sein:

 3 
 5 
 A 
 B 
 C 
 F 

Problem gelöst.

2
rsingh

min sort: 

#!/bin/bash
array=(.....)
index_of_element1=0

while (( ${index_of_element1} < ${#array[@]} )); do

    element_1="${array[${index_of_element1}]}"

    index_of_element2=$((index_of_element1 + 1))
    index_of_min=${index_of_element1}

    min_element="${element_1}"

        for element_2 in "${array[@]:$((index_of_element1 + 1))}"; do
            min_element="`printf "%s\n%s" "${min_element}" "${element_2}" | sort | head -n+1`"      
            if [[ "${min_element}" == "${element_2}" ]]; then
                index_of_min=${index_of_element2}
            fi
            let index_of_element2++
        done

        array[${index_of_element1}]="${min_element}"
        array[${index_of_min}]="${element_1}"

    let index_of_element1++
done
2
MathQues
array=(a c b f 3 5)
new_array=($(echo "${array[@]}" | sed 's/ /\n/g' | sort))    
echo ${new_array[@]}

der Echoinhalt von new_array lautet:

3 5 a b c f
1
blp

Wenn Sie für jedes Element im Array eine eindeutige Ganzzahl berechnen können, gehen Sie wie folgt vor:

tab='0123456789abcdefghijklmnopqrstuvwxyz'

# build the reversed ordinal map
for ((i = 0; i < ${#tab}; i++)); do
    declare -g ord_${tab:i:1}=$i
done

function sexy_int() {
    local sum=0
    local i ch ref
    for ((i = 0; i < ${#1}; i++)); do
        ch="${1:i:1}"
        ref="ord_$ch"
        (( sum += ${!ref} ))
    done
    return $sum
}

sexy_int hello
echo "hello -> $?"
sexy_int world
echo "world -> $?"

sie können diese Ganzzahlen dann als Arrayindizes verwenden, da Bash immer ein Array mit geringer Dichte verwendet, sodass Sie sich keine Sorgen über nicht verwendete Indizes machen müssen:

array=(a c b f 3 5)
for el in "${array[@]}"; do
    sexy_int "$el"
    sorted[$?]="$el"
done

echo "${sorted[@]}"
  • Pros Schnell.
  • Cons. Doppelte Elemente werden zusammengeführt, und es kann unmöglich sein, Inhalte 32-Bit-eindeutigen Ganzzahlen zuzuordnen.
1
Xiè Jìléi

Es gibt einen Workaround für das gewöhnliche Problem von Leerzeichen und Zeilenumbrüchen: 

Verwenden Sie ein Zeichen, das sich nicht im ursprünglichen Array befindet (wie $'\1' oder $'\4' oder ähnliches).

Diese Funktion erledigt die Arbeit:

# Sort an Array may have spaces or newlines with a workaround (wa=$'\4')
sortarray(){ local wa=$'\4' IFS=''
             if [[ $* =~ [$wa] ]]; then
                 echo "$0: error: array contains the workaround char" >&2
                 exit 1
             fi

             set -f; local IFS=$'\n' x nl=$'\n'
             set -- $(printf '%s\n' "${@//$nl/$wa}" | sort -n)
             for    x
             do     sorted+=("${x//$wa/$nl}")
             done
       }

Dadurch wird das Array sortiert:

$ array=( a b 'c d' $'e\nf' $'g\1h')
$ sortarray "${array[@]}"
$ printf '<%s>\n' "${sorted[@]}"
<a>
<b>
<c d>
<e
f>
<gh>

Dies beschwert sich, dass das Quell-Array das Problemumgehung enthält:

$ array=( a b 'c d' $'e\nf' $'g\4h')
$ sortarray "${array[@]}"
./script: error: array contains the workaround char

beschreibung

  • Wir setzen zwei lokale Variablen wa (Workaround-Zeichen) und ein Null-IFS
  • Dann (mit ifs null) testen wir das ganze Array $*.
  • Enthält kein Problemzeichen [[ $* =~ [$wa] ]].
  • Wenn dies der Fall ist, rufen Sie eine Nachricht aus und signalisieren Sie einen Fehler: exit 1
  • Vermeiden Sie Dateinamenerweiterungen: set -f
  • Legen Sie einen neuen Wert für IFS (IFS=$'\n'), eine Schleifenvariable x und eine Newline-Variable (nl=$'\n') fest.
  • Wir drucken alle Werte der erhaltenen Argumente (das Eingabearray [email protected]).
  • wir ersetzen jedoch jede neue Zeile durch den Workaround-Zeichen "${@//$nl/$wa}".
  • senden Sie diese Werte, um sortiert zu werden sort -n.
  • und platzieren Sie alle sortierten Werte in den Positionsargumenten set --.
  • Dann weisen wir jedes Argument einzeln zu (um die Zeilenumbrüche zu erhalten).
  • in einer Schleife for x
  • zu einem neuen Array: sorted+=(…)
  • anführungszeichen, um vorhandene Zeilenumbrüche zu erhalten.
  • wiederherstellen der Problemumgehung in einer neuen Zeile "${x//$wa/$nl}".
  • erledigt
0
sorontar

Ich bin nicht überzeugt, dass Sie ein externes Sortierprogramm in Bash benötigen.

Hier ist meine Implementierung für den einfachen Blasensortierungsalgorithmus.

function bubble_sort()
{   #
    # Sorts all positional arguments and echoes them back.
    #
    # Bubble sorting lets the heaviest (longest) element sink to the bottom.
    #
    local array=([email protected]) max=$(($# - 1))
    while ((max > 0))
    do
        local i=0
        while ((i < max))
        do
            if [ ${array[$i]} \> ${array[$((i + 1))]} ]
            then
                local t=${array[$i]}
                array[$i]=${array[$((i + 1))]}
                array[$((i + 1))]=$t
            fi
            ((i += 1))
        done
        ((max -= 1))
    done
    echo ${array[@]}
}

array=(a c b f 3 5)
echo " input: ${array[@]}"
echo "output: $(bubble_sort ${array[@]})"

Dies soll drucken:

 input: a c b f 3 5
output: 3 5 a b c f
0
a=(e b 'c d')
shuf -e "${a[@]}" | sort >/tmp/f
mapfile -t g </tmp/f
0
Steven Penny