585 Stimmen

Wie kann ich Elemente eines Arrays in der Bash verbinden?

Wenn ich ein Array wie dieses in Bash habe:

FOO=( a b c )

Wie verbinde ich die Elemente mit Kommas? Zum Beispiel, indem ich a,b,c .

1voto

TacB0sS Punkte 9806

Vielleicht komme ich zu spät zur Party, aber das funktioniert bei mir:

function joinArray() {
  local delimiter="${1}"
  local output="${2}"
  for param in ${@:3}; do
    output="${output}${delimiter}${param}"
  done

  echo "${output}"
}

1voto

Mark Pettit Punkte 143

Viele, wenn nicht sogar die meisten dieser Lösungen beruhen auf einer undurchsichtigen Syntax, hirnverbrannten Regex-Tricks oder Aufrufen externer ausführbarer Programme. Ich möchte eine einfache, nur auf Bash basierende Lösung vorschlagen, die sehr leicht zu verstehen ist und leistungsmäßig nur geringfügig suboptimal ist.

join_by () {
    # Argument #1 is the separator. It can be multi-character.
    # Argument #2, 3, and so on, are the elements to be joined.
    # Usage: join_by ", " "${array[@]}"
    local SEPARATOR="$1"
    shift

    local F=0
    for x in "$@"
    do
        if [[ F -eq 1 ]]
        then
            echo -n "$SEPARATOR"
        else
            F=1
        fi
        echo -n "$x"
    done
    echo
}

$ a=( 1 "2 2" 3 )
$ join_by ", " "${a[@]}"
1, 2 2, 3
$ 

Ich möchte darauf hinweisen, dass jede Lösung, die /usr/bin/[ o /usr/bin/printf ist inhärent langsamer als meine Lösung, da ich 100% reine Bash verwende. Als Beispiel für die Leistung, Hier ist eine Demo, wo ich ein Array mit 1.000.000 zufällige Ganzzahlen erstellen, dann verbinden sie alle mit einem Komma, und Zeit es.

$ eval $(echo -n "a=("; x=0 ; while [[ x -lt 1000000 ]]; do echo -n " $RANDOM" ; x=$((x+1)); done; echo " )")
$ time join_by , ${a[@]} >/dev/null
real    0m8.590s
user    0m8.591s
sys     0m0.000s
$

1voto

konsolebox Punkte 66082

Die Verwendung der Variablenumleitung, um direkt auf ein Array zu verweisen, funktioniert ebenfalls. Benannte Referenzen können ebenfalls verwendet werden, sind aber erst seit 4.3 verfügbar.

Der Vorteil dieser Form einer Funktion ist, dass das Trennzeichen optional sein kann (standardmäßig ist es das erste Zeichen der Standard IFS was ein Leerzeichen ist; machen Sie daraus vielleicht eine leere Zeichenkette, wenn Sie möchten), und es vermeidet, dass Werte zweimal expandiert werden (erstens, wenn sie als Parameter übergeben werden, und zweitens als "$@" innerhalb der Funktion).

Bei dieser Lösung ist es auch nicht erforderlich, dass der Benutzer die Funktion innerhalb einer Befehlssubstitution aufruft, die eine Subshell aufruft, um eine zusammengesetzte Version einer einer anderen Variablen zugewiesenen Zeichenkette zu erhalten.

function join_by_ref {
    __=
    local __r=$1[@] __s=${2-' '}
    printf -v __ "${__s//\%/%%}%s" "${!__r}"
    __=${__:${#__s}}
}

array=(1 2 3 4)

join_by_ref array
echo "$__" # Prints '1 2 3 4'.

join_by_ref array '%s'
echo "$__" # Prints '1%s2%s3%s4'.

join_by_ref 'invalid*' '%s' # Bash 4.4 shows "invalid*[@]: bad substitution".
echo "$__" # Prints nothing but newline.

Sie können auch einen bequemeren Namen für die Funktion verwenden.

Dies funktioniert von 3.1 bis 5.0-alpha. Wie beobachtet, funktioniert die Variablenumleitung nicht nur mit Variablen, sondern auch mit anderen Parametern.

Ein Parameter ist eine Einheit, die Werte speichert. Er kann ein Name sein, eine oder eines der Sonderzeichen sein, die unten unter Spezielle Parameter aufgeführt sind. Eine Variable ist ein Parameter, der durch einen Namen bezeichnet wird.

Arrays und Arrayelemente sind auch Parameter (Einheiten, die Werte speichern), und Verweise auf Arrays sind technisch gesehen ebenfalls Verweise auf Parameter. Und genau wie der spezielle Parameter @ , array[@] ist ebenfalls ein gültiger Hinweis.

Geänderte oder selektive Formen der Expansion (wie Teilstring-Expansion), die vom eigentlichen Parameter abweichen, funktionieren nicht mehr.

Update

In der Release-Version von Bash 5.0, variable Umlenkung wird bereits aufgerufen indirekte Ausweitung und sein Verhalten ist bereits ausdrücklich im Handbuch dokumentiert:

Wenn das erste Zeichen des Parameters ein Ausrufezeichen (!) ist, und Parameter kein nameref ist, führt er eine Umleitungsebene ein. Die Bash verwendet den Wert, der durch Expandieren des Rests von parameter gebildet wird, als neuen Parameter; dieser wird dann expandiert und der Wert wird in der Rest der Expansion verwendet, anstatt die Expansion des ursprünglichen Parameters. Dies wird als indirekte Expansion bezeichnet.

Es wird darauf hingewiesen, dass in der Dokumentation von ${parameter} , parameter wird bezeichnet als "ein Shell-Parameter wie in PARAMETERS beschrieben oder ein Array-Referenz ". Und in der Dokumentation von Arrays wird erwähnt, dass "Auf jedes Element eines Arrays kann mit ${name[subscript]} ". Dies macht __r[@] eine Array-Referenz.

Verbinden durch Argumente Version

Siehe meine Kommentar in Antwort von Riccardo Galli .

1voto

Daniel Patru Punkte 1900

Verwenden Sie Perl für mehrstellige Trennzeichen:

function join {
   perl -e '$s = shift @ARGV; print join($s, @ARGV);' "$@"; 
}

join ', ' a b c # a, b, c

Oder in einer Zeile:

perl -le 'print join(shift, @ARGV);' ', ' 1 2 3
1, 2, 3

1voto

Ian Kelling Punkte 9144

Wenn Sie das Array in einer Schleife aufbauen, ist dies ein einfacher Weg:

arr=()
for x in $(some_cmd); do
   arr+=($x,)
done
arr[-1]=${arr[-1]%,}
echo ${arr[*]}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X