Ich habe ein Array, das mit verschiedenen Fehlermeldungen gefüllt wird, während mein Skript ausgeführt wird.
Ich brauche eine Möglichkeit, um zu überprüfen, ob es am Ende des Skripts leer ist, und eine bestimmte Aktion auszuführen, wenn dies der Fall ist.
Ich habe bereits versucht, es wie eine normale VAR zu behandeln und es 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?
=
ein String-Operator ist. In diesem Fall funktioniert es problemlos, aber ich verwende-eq
stattdessen den richtigen arithmetischen Operator (nur für den Fall, dass ich zu-ge
oder wechseln möchte-lt
usw.).set -u
: "ungebundene Variable" - wenn das Array leer ist.set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. Wenn ichunset foo
, dann druckt esfoo: unbound variable
, aber das ist anders: Die Array-Variable existiert überhaupt nicht, anstatt zu existieren und leer zu sein.set -u
- solange Sie Ihre Variable zuerst deklariert haben, funktioniert dies einwandfrei.In diesem Fall verwende ich in der Regel die arithmetische Erweiterung:
quelle
(( ${#a} ))
(Länge des ersten Elements) auch funktioniert. Dies wird jedoch fehlschlagena=('')
, wohingegen(( ${#a[@]} ))
die Antwort Erfolg haben wird.Sie können das Array auch als einfache Variable betrachten. Auf diese Weise nur mit
oder mit der anderen Seite
Das Problem bei dieser Lösung besteht darin , dass , wenn ein Array wie folgt erklärt:
array=('' foo)
. Bei diesen Überprüfungen wird das Array als leer gemeldet, während dies eindeutig nicht der Fall ist. (danke @musiphil!)Verwenden
[ -z "$array[@]" ]
ist natürlich auch keine Lösung. Wenn geschweifte Klammern nicht angegeben werden, wird versucht, sie$array
als Zeichenfolge zu interpretieren ([@]
ist in diesem Fall eine einfache Literalzeichenfolge) und wird daher immer als falsch gemeldet: "Ist die Literalzeichenfolge[@]
leer?" Ganz sicher nicht.quelle
[ -z "$array" ]
oder[ -n "$array" ]
funktioniert nicht. Versuchen Sie esarray=('' foo); [ -z "$array" ] && echo empty
, und es wird gedrucktempty
, obwohlarray
es eindeutig nicht leer ist.[[ -n "${array[*]}" ]]
interpoliert das gesamte Array als Zeichenfolge, die Sie auf eine Länge ungleich Null überprüfen. Wenn Sie der Ansicht sindarray=("" "")
, leer zu sein, anstatt zwei leere Elemente zu haben, kann dies nützlich sein.[[ -n " " ]]
ergibt ein einzelnes Leerzeichen und ist "wahr", was sehr schade ist. Dein Kommentar ist genau das, was ich will zu tun.set -x
zeigt wie es sich ausdehnt. Ich glaube, ich habe diesen Kommentar vor dem Posten nicht getestet. >. <Sie können es zum Laufen bringen, indemIFS=''
Sie diese Anweisung festlegen (speichern / wiederherstellen), da die"${array[*]}"
Erweiterung Elemente mit dem ersten IFS-Zeichen voneinander trennt. (Oder Leerzeichen, wenn nicht gesetzt). Aber " Wenn IFS null ist, werden die Parameter ohne Trennzeichen verbunden. " (Docs für $ * -Positionsparameter, aber ich nehme dasselbe für Arrays an).Ich habe es überprüft mit
bash-4.4.0
:und
bash-4.1.5
:Im letzteren Fall benötigen Sie folgendes Konstrukt:
Damit es bei leeren oder nicht gesetzten Arrays nicht fehlschlägt. Das ist, wenn Sie tun,
set -eu
wie ich es normalerweise tue. Dies sorgt für eine strengere Fehlerprüfung. Aus den Dokumenten :Wenn Sie das nicht benötigen, können Sie einen
:+${array[@]}
Teil weglassen .Auch merken Sie , dass es wichtig ist , zu verwenden
[[
Operator hier, mit[
Ihnen zu bekommen:quelle
-u
sollten Sie tatsächlich nutzen${array[@]+"${array[@]}"}
cf stackoverflow.com/a/34361807/1237617@
sicherlich das. Sie könnten eine*
Array-Erweiterung verwenden[ "${array[*]}" ]
, oder nicht? Funktioniert trotzdem[[
auch prima. Das Verhalten von beiden für ein Array mit mehreren leeren Zeichenfolgen ist ein wenig überraschend. Beide[ ${#array[*]} ]
und[[ "${array[@]}" ]]
sind falsch fürarray=()
undarray=('')
aber wahr fürarray=('' '')
(zwei oder mehr leere Zeichenketten). Wenn Sie möchten, dass eine oder mehrere leere Zeichenfolgen wahr sind, können Sie sie verwenden[ ${#array[@]} -gt 0 ]
. Wenn du willst, dass sie alle falsch sind, könntest du sie vielleicht//
rausholen.[ "${array[*]}" ]
, aber wenn ich auf einen solchen Ausdruck stoßen würde, wäre es schwieriger für mich zu verstehen, was er tut. Da[...]
arbeitet in Strings das Ergebnis der Interpolation ab. Im Gegensatz zu[[...]]
, die wissen können, was interpoliert wurde. Das heißt, es kann wissen, dass ein Array übergeben wurde.[[ ${array[@]} ]]
liest für mich als "überprüfe, ob das Array nicht leer ist", während[ "${array[*]}" ]
als "überprüfe, ob das Ergebnis der Interpolation aller Array-Elemente ein nicht leerer String ist".[ ${#array[*]} ]
, meinten Sie wahrscheinlich[ "${array[*]}" ]
, da ersteres für eine beliebige Anzahl von Elementen gilt. Weil die Anzahl der Elemente immer eine nicht leere Zeichenfolge ist. Bei letzterem mit zwei Elementen erweitert sich der Ausdruck in Klammern zu einer' '
nicht leeren Zeichenfolge. Was[[ ${array[@]} ]]
denken sie nur (zu Recht) , daß jede Reihe von zwei Elementen nicht leer ist .Wenn Sie ein Array mit leeren Elementen erkennen möchten , z. B.
arr=("" "")
so leer wiearr=()
Sie können alle Elemente zusammenfügen und prüfen, ob das Ergebnis eine Länge von Null hat. (Das Erstellen einer reduzierten Kopie des Array-Inhalts ist für die Leistung nicht ideal, wenn das Array sehr groß sein könnte. Hoffentlich verwenden Sie bash nicht für solche Programme ...)
Erweitert
"${arr[*]}"
sich jedoch mit Elementen, die durch das erste Zeichen vonIFS
. Sie müssen also IFS speichern / wiederherstellen und dafürIFS=''
sorgen, dass dies funktioniert, oder Sie müssen überprüfen, ob die Zeichenfolgenlänge == # der Array-Elemente - 1 ist. (Ein Array vonn
Elementen verfügt übern-1
Trennzeichen.) Um dieses Problem zu lösen, ist es am einfachsten, die Verkettung mit 1 aufzufüllenTestfall mit
set -x
Leider ist diese nicht für
arr=()
:[[ 1 -ne 0 ]]
. Sie müssen also zuerst separat nach tatsächlich leeren Arrays suchen.Oder mit
IFS=''
. Wahrscheinlich möchten Sie IFS speichern / wiederherstellen, anstatt eine Subshell zu verwenden, da Sie mit einer Subshell nicht einfach ein Ergebnis erzielen können.Beispiel:
funktioniert mit
arr=()
- es ist immer noch nur die leere Zeichenfolge.quelle
[[ "${arr[*]}" = *[![:space:]]* ]]
, da ich mich auf mindestens einen Nicht-WS-Charakter verlassen kann.arr=(" ")
.In meinem Fall war die zweite Antwort nicht genug, weil es Leerzeichen geben könnte. Ich kam mit:
quelle
echo | wc
scheint unnötig ineffizient im Vergleich zu Shell-Built-Ins.[ ${#errors[@]} -eq 0 ];
das Leerzeichenproblem umgangen wird ? Ich würde auch den eingebauten bevorzugen.$#
wird zu einer Zahl erweitert und funktioniert auch danach noch einwandfreiopts+=("")
. zBunset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
und ich bekomme2
. Können Sie ein Beispiel für etwas zeigen, das nicht funktioniert?opts=("")
genauso behandeln wieopts=()
? Das ist kein leeres Array, aber Sie können mit auf leeres Array oder leeres erstes Element prüfenopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
. Beachten Sie, dass Ihre aktuelle Antwort "no options" füropts=("" "-foo")
lautet, was völlig falsch ist, und dies dieses Verhalten reproduziert. Sie können sich[[ -z "${opts[*]}" ]]
vorstellen, alle Array-Elemente in eine flache Zeichenfolge zu interpolieren, die nach einer-z
Länge ungleich Null sucht. Wenn die Überprüfung des ersten Elements ausreicht,-z "$opts"
funktioniert.Ich bevorzuge doppelte Klammern:
quelle