Sprawdź, czy zmienna jest ustawiona w bash, używając „set -o nounset”

99

Poniższy kod kończy działanie z niepowiązanym błędem zmiennej. Jak to naprawić, nadal używając set -oopcji rzeczownika?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"
vinodkone
źródło

Odpowiedzi:

100
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

W tym przypadku VALUEkończy się jako pusty łańcuch, jeśli WHATEVERnie jest ustawiony. Używamy {parameter:-word}rozszerzenia, które możesz sprawdzić w man bashsekcji „Rozszerzenie parametrów”.

Angelom
źródło
15
po prostu wymień, jeśli [! -z $ {VALUE}]; z if [! -z $ {WSZYSTKO: -}];
Angelom
18
:-sprawdza, czy zmienna jest nieustawiona lub pusta. Jeśli chcesz sprawdzić tylko , czy jest wyłączony, należy -: VALUE=${WHATEVER-}. Ponadto czytelniejszy sposób sprawdzenia, czy zmienna jest pusta:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0
1
To nie zadziała, jeśli $WHATEVERzawiera tylko spacje - Zobacz moją odpowiedź.
l0b0
11
Czy istnieje powód używania „ ! -z” zamiast tylko „ -n”?
Jonathan Hartley
32

Musisz zacytować zmienne, jeśli chcesz uzyskać oczekiwany wynik:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Test:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty
l0b0
źródło
Próbowałem tego i jestem zaskoczony, to działa ... Wszystko się zgadza z wyjątkiem według "info bash", "${WHATEVER-}"powinien mieć ":"(dwukropek) przed "-"(myślnik), takich jak: "${WHATEVER:-}"i "${WHATEVER+defined}"powinien mieć dwukropek przed "+"(plus), takich jak: "${WHATEVER:+defined}". U mnie działa to w obie strony, z okrężnicą lub bez. W niektórych wersjach 'nix prawdopodobnie nie zadziała bez uwzględnienia dwukropka, więc prawdopodobnie powinno zostać dodane.
Kevin Fegan,
8
Nie, -, +, :+, i :-są obsługiwane. Pierwsza wykrywa, czy zmienna jest ustawiona , a druga, czy jest ustawiona, czy pusta . Od man bash: „Pominięcie dwukropka powoduje test tylko dla nieustawionego parametru”.
l0b0
1
Nieważne =). Masz rację. Nie wiem, jak to przegapiłem.
Kevin Fegan
Z dokumentacji : Innymi słowy, jeśli uwzględniono dwukropek, operator sprawdza istnienie obu parametrów i czy ich wartość nie jest zerowa; jeśli dwukropek zostanie pominięty, operator sprawdza tylko istnienie.
Acumenus
11

A może oneliner?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z sprawdza zarówno pustą, jak i nieustawioną zmienną

NublaII
źródło
2
Nie, -zsprawdza tylko, czy następny parametr jest pusty. -zjest tylko argumentem [polecenia. Zmienna ekspansja ma miejsce, zanim [ -zcokolwiek zrobi.
dolmen
1
Wydaje się, że jest to właściwe rozwiązanie, ponieważ nie generuje błędu, jeśli parametr $ VAR nie jest ustawiony. @dolmen Czy możesz podać przykład, kiedy to nie zadziała?
Chris Stryczynski
@dolmen po przeczytaniu różnych zasobów bash na temat rozszerzania parametrów i znajdowaniu innych odpowiedzi zbyt skomplikowanych, nie widzę w tym nic złego. więc twoje „wyjaśnienie”, chociaż technicznie poprawne, wydaje się raczej bezcelowe w praktyce, chyba że musisz odróżnić stan nieustawiony od pustego. Testowałem nieustawiony, pusty i niepusty (bash 4) i za każdym razem robiłem to, co było reklamowane.
JL Peyret,
9

Założenia:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Jeśli chcesz, aby nieinteraktywny skrypt wyświetlał błąd i kończył pracę, jeśli zmienna ma wartość null lub nie jest ustawiona:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Jeśli nie chcesz, aby skrypt kończył się:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Możesz nawet użyć [i ]zamiast [[i ]]powyżej, ale ten drugi jest lepszy w Bash.

Zwróć uwagę, co robi dwukropek powyżej. Z dokumentów :

Innymi słowy, jeśli uwzględniono dwukropek, operator sprawdza istnienie obu parametrów i czy ich wartość nie jest zerowa; jeśli dwukropek zostanie pominięty, operator sprawdza tylko istnienie.

Najwyraźniej nie ma potrzeby -nlub -z.

Podsumowując, zwykle mogę po prostu użyć [[ "${VAR:?}" ]] . Zgodnie z przykładami, to wyświetla błąd i kończy działanie, jeśli zmienna ma wartość null lub nie jest ustawiona.

Acumenus
źródło
4

Możesz użyć

if [[ ${WHATEVER:+$WHATEVER} ]]; then

ale

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

może być bardziej czytelny.

Aleš Friedl
źródło
Porównania ciągów powinny używać =operatora standardowego (POSIX) , a nie w ==celu ułatwienia przenoszenia, a [zamiast tego, [[jeśli to możliwe.
Jens
2
@Jens Pytanie dotyczy tylko basha i obejmuje set -o nounsetto, co jest specyficzne dla basha. Jeśli umieścisz znak #!/bin/bashna górze swojego skryptu, najlepiej jest użyć ulepszeń basha.
Bruno Bronosky
0

Chociaż nie jest to dokładnie ten przypadek użycia, o który pytano powyżej, odkryłem, że jeśli chcesz użyć nounset(lub -u), domyślne zachowanie jest takie, jakie chcesz: wyjście niezerowe z komunikatem opisowym.

Zajęło mi wystarczająco dużo czasu, zanim zdałem sobie z tego sprawę, i pomyślałem, że warto go opublikować jako rozwiązanie.

Jeśli chcesz tylko powtórzyć coś innego podczas wychodzenia lub wykonać jakieś czyszczenie, możesz użyć pułapki.

W :-przeciwnym razie operator jest prawdopodobnie tym, czego chcesz.

Max Bileschi
źródło