Mam tablicę, która wypełnia się różnymi komunikatami o błędach podczas działania mojego skryptu.
Potrzebuję sposobu, aby sprawdzić, czy nie jest pusty na końcu skryptu i podjąć konkretne działanie, jeśli tak jest.
Próbowałem już traktować to jak normalną VAR i używać -z, aby to sprawdzić, ale to nie działa. Czy istnieje sposób sprawdzenia, czy tablica jest pusta, czy nie w Bash?
=
jest to operator łańcuchowy. Zdarza się, że w tym przypadku działa dobrze, ale-eq
zamiast tego użyłbym właściwego operatora arytmetycznego (na wypadek, gdyby chciałem przełączyć na-ge
lub-lt
, itp.).set -u
: „zmienną niezwiązaną” - jeśli tablica jest pusta.set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. Jeśli jaunset foo
, to drukujefoo: unbound variable
, ale jest inaczej: zmienna tablicowa w ogóle nie istnieje, a nie istnieje i jest pusta.set -u
- dopóki zadeklarujesz swoją zmienną jako pierwszą, działa to doskonale.Zwykle używam rozszerzenia arytmetycznego w tym przypadku:
źródło
(( ${#a} ))
(długość pierwszego elementu) również będzie działać. To się jednak nie powiedziea=('')
, a odpowiedź(( ${#a[@]} ))
podana w odpowiedzi się powiedzie.Możesz także rozważyć tablicę jako prostą zmienną. W ten sposób po prostu używam
lub używając drugiej strony
Problem z tego rozwiązania jest to, że jeśli tablica jest zadeklarowana następująco:
array=('' foo)
. Te kontrole zgłoszą tablicę jako pustą, podczas gdy wyraźnie nie jest. (dzięki @musiphil!)Używanie nie
[ -z "$array[@]" ]
jest oczywiście rozwiązaniem. Brak określenia nawiasów klamrowych próbuje interpretować$array
jako ciąg znaków ([@]
w takim przypadku jest to zwykły ciąg literałów) i dlatego jest zawsze zgłaszany jako fałsz: „czy ciąg literałów jest[@]
pusty?” Najwyraźniej nie.źródło
[ -z "$array" ]
lub[ -n "$array" ]
nie działa. Spróbujarray=('' foo); [ -z "$array" ] && echo empty
, a wydrukuje się,empty
mimo żearray
wyraźnie nie jest pusty.[[ -n "${array[*]}" ]]
interpoluje całą tablicę jako ciąg, który sprawdza się pod kątem niezerowej długości. Jeśli uważasz, żearray=("" "")
jest pusty, zamiast mieć dwa puste elementy, może to być przydatne.[[ -n " " ]]
jest „prawdziwe”, a szkoda. Twój komentarz jest dokładnie tym, co chcę zrobić.set -x
pokazuje, jak się rozwija. Chyba nie przetestowałem tego komentarza przed opublikowaniem. >. <Możesz sprawić, aby działał, ustawiającIFS=''
(zapisz / przywróć go wokół tej instrukcji), ponieważ"${array[*]}"
interpretacja oddziela elementy pierwszym znakiem IFS. (Lub spacja, jeśli nie jest ustawiona). Ale „ Jeśli IFS ma wartość NULL, parametry są łączone bez ingerencji w separatory. ” (Dokumenty dla parametrów pozycyjnych $ *, ale zakładam to samo dla tablic).Sprawdziłem to za pomocą
bash-4.4.0
:i
bash-4.1.5
:W tym drugim przypadku potrzebujesz następującej konstrukcji:
aby nie zawiodła na pustej lub nieuzbrojonej tablicy. Tak, jeśli robisz tak
set -eu
jak zwykle. Zapewnia to bardziej rygorystyczne sprawdzanie błędów. Z dokumentów :Jeśli nie potrzebujesz tego, możesz pominąć
:+${array[@]}
część.Zauważ też, że konieczne jest
[[
tutaj korzystanie z operatora, ponieważ[
otrzymasz:źródło
-u
tym powinieneś faktycznie skorzystać z${array[@]+"${array[@]}"}
cf stackoverflow.com/a/34361807/1237617@
pewnością. Możesz użyć*
rozszerzenia tablicy[ "${array[*]}" ]
, prawda? Nadal[[
działa również dobrze. Zachowanie obu z nich dla tablicy z wieloma pustymi łańcuchami jest nieco zaskakujące. Oba[ ${#array[*]} ]
i[[ "${array[@]}" ]]
są fałszywe dlaarray=()
iarray=('')
ale prawdziwe dlaarray=('' '')
(dwóch lub więcej pustych ciągów). Jeśli chcesz, aby jeden lub więcej pustych ciągów zawierało wartość true, możesz użyć[ ${#array[@]} -gt 0 ]
. Jeśli chcesz, aby wszystkie były fałszywe, być może możesz//
je usunąć.[ "${array[*]}" ]
, ale gdybym wpadł na takie wyrażenie, trudniej byłoby mi zrozumieć, co robi. Ponieważ[...]
działa w kategoriach ciągów na wyniku interpolacji. W przeciwieństwie do[[...]]
, które mogą być świadome tego, co zostało interpolowane. Oznacza to, że może wiedzieć, że przekazano tablicę.[[ ${array[@]} ]]
czyta mi jako „sprawdź, czy tablica nie jest pusta”, a[ "${array[*]}" ]
jako „sprawdź, czy wynikiem interpolacji wszystkich elementów tablicy jest niepusty ciąg”.[ ${#array[*]} ]
, prawdopodobnie miałeś na myśli[ "${array[*]}" ]
, ponieważ to pierwsze jest prawdziwe dla dowolnej liczby elementów. Ponieważ liczba elementów jest zawsze niepustym łańcuchem. Jeśli chodzi o ten drugi element z dwoma elementami, wyrażenie w nawiasach interpretacyjnych jest interpretowane jako' '
niepusty ciąg. Co do tego[[ ${array[@]} ]]
, po prostu myślą (i słusznie), że jakakolwiek tablica dwóch elementów nie jest pusta.Jeśli chcesz wykryć tablicę z pustymi elementami , jak
arr=("" "")
pusta, taka sama jakarr=()
Możesz wkleić wszystkie elementy razem i sprawdzić, czy wynik ma zerową długość. (Budowanie spłaszczonej kopii zawartości tablicy nie jest idealne pod względem wydajności, jeśli tablica może być bardzo duża. Miejmy nadzieję, że nie używasz bash dla takich programów ...)
Ale
"${arr[*]}"
rozwija się z elementami oddzielonymi przez pierwszą postaćIFS
. Musisz więc zapisać / przywrócić IFS i zrobić,IFS=''
aby to działało, albo sprawdź, czy długość łańcucha == # elementów tablicy - 1. (Tablican
elementów man-1
separatory). Aby poradzić sobie z tym osobno, najłatwiej jest uzupełnić konkatenację o 1walizka testowa z
set -x
Niestety to nie powiedzie
arr=()
:[[ 1 -ne 0 ]]
. Dlatego najpierw trzeba osobno sprawdzić, czy rzeczywiście są puste tablice.Lub z
IFS=''
. Prawdopodobnie chcesz zapisać / przywrócić IFS zamiast używać podpowłoki, ponieważ nie możesz łatwo uzyskać wyniku z podpowłoki.przykład:
ma pracować
arr=()
- to wciąż tylko pusty ciąg.źródło
[[ "${arr[*]}" = *[![:space:]]* ]]
, ponieważ mogę liczyć na co najmniej jedną postać spoza WS.arr=(" ")
.W moim przypadku druga odpowiedź nie była wystarczająca, ponieważ mogły istnieć białe spacje. Przyszłam z:
źródło
echo | wc
wydaje się niepotrzebnie nieefektywne w porównaniu z wbudowanymi powłokami.[ ${#errors[@]} -eq 0 ];
w celu obejścia problemu z białymi znakami ? Wolałbym również wbudowany.$#
rozwija się do liczby i działa dobrze nawet poopts+=("")
. np.unset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
i dostaję2
. Czy możesz pokazać przykład czegoś, co nie działa?opts=("")
tak samo jakopts=()
? To nie jest pusta tablica, ale możesz sprawdzić pustą tablicę lub pusty pierwszy element za pomocąopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
. Zauważ, że twoja obecna odpowiedź mówi „brak opcji” dlaopts=("" "-foo")
, co jest całkowicie fałszywe, a to odtwarza to zachowanie. Można[[ -z "${opts[*]}" ]]
Chyba, interpolować wszystkie elementy tablicy do płaskiej ciąg, który-z
sprawdza czy długość niezerową. Jeśli sprawdzenie pierwszego elementu jest wystarczające,-z "$opts"
działa.Wolę używać podwójnych nawiasów:
źródło