Frage Überprüfen Sie, ob das Array in Bash leer ist


Ich habe ein Array, das mit verschiedenen Fehlermeldungen gefüllt wird, während mein Skript läuft.

Ich brauche einen Weg, um zu überprüfen, ob es nicht am Ende des Skripts leer ist, und eine bestimmte Aktion auszuführen, wenn dies der Fall ist.

Ich habe bereits versucht, es wie einen normalen VAR zu behandeln und mit -z zu überprüfen, aber das scheint nicht zu funktionieren. Gibt es eine Möglichkeit zu überprüfen, ob ein Array in Bash leer ist oder nicht?

Vielen Dank


82
2018-02-11 03:59


Ursprung




Antworten:


Angenommen, Ihr Array ist $errorsÜberprüfen Sie einfach, ob die Anzahl der Elemente null ist.

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi

113
2018-02-11 04:10



Bitte beachte, dass = ist ein String-Operator. Es funktioniert in diesem Fall gut, aber ich würde den richtigen arithmetischen Operator verwenden -eq stattdessen (nur für den Fall, dass ich zu wechseln würde -ge oder -lt, usw.). - musiphil
Funktioniert nicht mit set -u: "nicht gebundene Variable" - wenn das Array leer ist. - Igor
@Igor: Funktioniert für mich in Bash 4.4. set -u;  foo=();  [ ${#foo[@]} -eq 0 ] && echo empty. Wenn ich unset fooDann druckt es foo: unbound variable, aber das ist anders: Die Array-Variable existiert überhaupt nicht, sondern existiert und ist leer. - Peter Cordes
Auch getestet in Bash 3.2 (OSX) bei der Verwendung set -u - Solange Sie Ihre Variable zuerst deklariert haben, funktioniert das perfekt. - zeroimpl


Sie können das Array auch als einfache Variable betrachten. Auf diese Weise einfach verwenden

if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi

oder mit der anderen Seite

if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi

Das Problem mit dieser Lösung besteht darin, dass ein Array wie folgt deklariert wird: array=('' foo). Diese Überprüfungen melden das Array als leer, während dies eindeutig nicht der Fall ist. (Danke @musiphil!)

Verwenden [ -z "$array[@]" ] ist eindeutig auch keine Lösung. Nicht angegebene geschweifte Klammern versuchen zu interpretieren $array als eine Schnur ([@] ist in diesem Fall eine einfache Literal-Zeichenkette) und wird daher immer als falsch gemeldet: "ist die Literal-Zeichenkette [@] leer? "Offensichtlich nicht.


6
2018-06-23 10:29



[ -z "$array" ] oder [ -n "$array" ] funktioniert nicht. Versuchen array=('' foo); [ -z "$array" ] && echo emptyund es wird gedruckt empty obwohl array ist eindeutig nicht leer. - musiphil
[[ -n "${array[*]}" ]] interpoliert das gesamte Array als String, den Sie auf eine Länge ungleich Null prüfen. Wenn Sie darüber nachdenken array=("" "") um leer zu sein, anstatt zwei leere Elemente zu haben, könnte dies nützlich sein. - Peter Cordes


Ich benutze in der Regel arithmetische Expansion in diesem Fall:

if (( ${#a[@]} )); then
    echo not empty
fi

3
2017-08-02 06:04



Schön und sauber! Ich mag das. Ich merke auch, dass, wenn das erste Element des Arrays immer nicht leer ist, (( ${#a} )) (Länge des ersten Elements) wird auch funktionieren. Das wird jedoch scheitern a=(''), wohingegen (( ${#a[@]} )) gegeben in der Antwort wird gelingen. - cxw


Ich habe es überprüft bash-4.4.0:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

und bash-4.1.5:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

Im letzteren Fall benötigen Sie das folgende Konstrukt:

${array[@]:+${array[@]}}

damit es bei einem leeren oder nicht gesetzten Array nicht fehlschlägt. Wenn du es tust set -eu wie ich es normalerweise tue. Dies ermöglicht eine strengere Fehlerprüfung. Von die Dokumente:

-e

Beenden Sie sofort, wenn eine Pipeline (siehe Pipelines), die aus einem einzelnen einfachen Befehl (siehe Einfache Befehle), einer Liste (siehe Listen) oder einem zusammengesetzten Befehl (siehe Zusammengesetzte Befehle) bestehen kann, einen Nicht-Null-Status zurückgibt. Die Shell wird nicht beendet, wenn der Befehl, der fehlschlägt, Teil der Befehlsliste ist, unmittelbar nach einer Weile oder bis Schlüsselwort, Teil des Tests in einer if-Anweisung, Teil eines Befehls, der in einem && oder || ausgeführt wird Liste mit Ausnahme des Befehls nach dem abschließenden && oder ||, einem beliebigen Befehl in einer Pipeline, aber dem letzten, oder wenn der Rückgabestatus des Befehls mit! invertiert wird. Wenn ein anderer Compound-Befehl als eine Subshell einen Status ungleich Null zurückgibt, weil ein Befehl fehlgeschlagen ist, während -e ignoriert wurde, wird die Shell nicht beendet. Ein Trap auf ERR, falls gesetzt, wird ausgeführt, bevor die Shell beendet wird.

Diese Option gilt für die Shell-Umgebung und jede Subshell-Umgebung separat (siehe Befehlsausführungsumgebung) und kann dazu führen, dass Subshells beendet werden, bevor alle Befehle in der Subshell ausgeführt werden.

Wenn ein Compound-Befehl oder eine Shell-Funktion in einem Kontext ausgeführt wird, in dem -e ignoriert wird, wird keiner der Befehle, die im Compound-Befehl oder -Funktionskörper ausgeführt werden, von der Einstellung -e beeinflusst, selbst wenn -e gesetzt ist und ein Befehl a zurückgibt Fehlerstatus. Wenn ein zusammengesetzter Befehl oder eine Shell-Funktion -e während der Ausführung in einem Kontext setzt, in dem -e ignoriert wird, hat diese Einstellung keine Auswirkungen, bis der zusammengesetzte Befehl oder der Befehl, der den Funktionsaufruf enthält, abgeschlossen sind.

-u

Behandeln Sie nicht gesetzte Variablen und andere Parameter als die speziellen Parameter '@' oder '*' als Fehler, wenn Sie die Parametererweiterung durchführen. Eine Fehlermeldung wird in den Standardfehler geschrieben, und eine nicht interaktive Shell wird beendet.

Wenn Sie das nicht brauchen, können Sie es auslassen :+${array[@]} Teil.

Beachten Sie auch, dass es wichtig ist zu verwenden [[ Betreiber hier mit [ du kriegst:

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty

2
2017-12-04 14:58



Mit -u Du solltest es tatsächlich benutzen ${array[@]+"${array[@]}"} vgl stackoverflow.com/a/34361807/1237617 - Jakub Bochenski
@JakubBochenski Über welche Version von Bash sprichst du? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9 - x-yuri
Das Problem im Beispiel der einzelnen Klammern ist das @Sicherlich. Du könntest benutzen * Array-Erweiterung wie [ "${array[*]}" ], könntest du nicht? Immer noch, [[ funktioniert auch gut. Das Verhalten beider für ein Array mit mehreren leeren Strings ist ein wenig überraschend. Beide [ ${#array[*]} ] und [[ "${array[@]}" ]] sind falsch für array=() und array=('') aber wahr für array=('' '') (zwei oder mehr leere Zeichenfolgen). Wenn Sie eine oder mehrere leere Zeichenfolgen für alle wahr geben möchten, könnten Sie verwenden [ ${#array[@]} -gt 0 ]. Wenn du sie alle falsch haben wolltest, könntest du vielleicht // die raus. - eisd
@eisd könnte ich benutzen [ "${array[*]}" ], aber wenn ich auf einen solchen Ausdruck stoßen würde, wäre es für mich schwerer zu verstehen, was es tut. Schon seit [...] arbeitet in Strings als Ergebnis der Interpolation. Im Gegensatz zu [[...]], die wissen, was interpoliert wurde. Das heißt, es kann wissen, dass es ein Array übergeben wurde. [[ ${array[@]} ]] liest mir als "überprüfe, ob Array nicht leer ist", während [ "${array[*]}" ] als "überprüfe, ob das Ergebnis der Interpolation aller Array-Elemente eine nicht leere Zeichenfolge ist". - x-yuri
... Was das Verhalten mit zwei leeren Saiten betrifft, ist es für mich nicht überraschend. Überraschend ist das Verhalten mit einer leeren Saite. Aber wohl vernünftig. Bezüglich [ ${#array[*]} ]Wahrscheinlich hast du es gemeint [ "${array[*]}" ], da ersteres für eine beliebige Anzahl von Elementen gilt. Weil die Anzahl der Elemente immer eine nicht leere Zeichenfolge ist. Bezüglich letzterer mit zwei Elementen erweitert sich der Ausdruck in Klammern zu ' ' Das ist keine leere Zeichenfolge. Wie für [[ ${array[@]} ]]denken sie (und zu Recht), dass jede Anordnung von zwei Elementen nicht leer ist. - x-yuri


In meinem Fall, der zweite Antwort war nicht genug, weil es Whitespaces geben konnte. Ich kam mit:

if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
  echo "No options"
else
  echo "Options found"
fi

0
2018-02-17 19:54



echo | wc scheint unnötig ineffizient im Vergleich mit Shell-Einbauten zu sein. - Peter Cordes
Nicht sicher, ob ich @PeterCordes verstehe, kann ich die zweiten Antworten ändern ' [ ${#errors[@]} -eq 0 ]; um das Whitespace Problem zu umgehen? Ich würde auch das eingebaute bevorzugen. - Micha
Wie genau verursacht Whitespace ein Problem? $# expandiert zu einer Zahl und funktioniert auch nachher gut opts+=(""). z.B. unset opts;  opts+=("");opts+=(" "); echo "${#opts[@]}" und ich bekomme 2. Können Sie ein Beispiel für etwas zeigen, das nicht funktioniert? - Peter Cordes
Es ist lange her. IIRC die Ursprungsquelle immer mindestens gedruckt "". Also, für opts = "" oder opts = ("") brauchte ich 0, nicht 1, ignoriere die leere Newline oder leere Zeichenfolge. - Micha
Ok, also musst du behandeln opts=("") das Gleiche wie opts=()? Das ist kein leeres Array, aber Sie können nach einem leeren Array oder einem leeren ersten Element suchen opts=("");  [[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty. Beachten Sie, dass Ihre aktuelle Antwort "keine Optionen" für lautet opts=("" "-foo")das ist völlig falsch, und das reproduziert dieses Verhalten. Du könntest [[ -z "${opts[*]}" ]] Ich schätze, alle Array-Elemente zu einer flachen Zeichenfolge zu interpolieren, die -z prüft auf Länge ungleich Null.  Wenn die Überprüfung des ersten Elements ausreicht, -z "$opts" funktioniert. - Peter Cordes


Ich bevorzuge doppelte Klammern:

if [[ !${array[@]} ]]
then
    echo "Array is empty"
else
    echo "Array is not empty"
fi

Doppelwinkel: https://StackOverflow.com/questions/669452/is-bevorzugbare-over-in-bash


0
2017-11-04 06:40