Testowanie, czy zmienna jest pusta w skrypcie powłoki


27

Widziałem następującą technikę stosowaną wiele razy w wielu różnych powłokach, aby sprawdzić, czy zmienna jest pusta:

if [ "x$1" = "x" ]; then 
    # Variable is empty
fi

Czy są jakieś zalety korzystania z tego w porównaniu z bardziej kanonicznymi if [ -z "$1" ]? Czy może to być problem z przenośnością?

Odpowiedzi:


17

Niektóre historyczne powłoki zaimplementowały bardzo prosty analizator składni, który mógł zostać pomylony przez rzeczy, takie jak to, [ -n = "" ]gdzie pierwszy operand =wygląda jak operator, i parsowałby to jako [ -n = ]lub spowodował błąd składniowy. W [ "x$1" = x"" ], na x, zapewnia prefiks, który x"$1"nie może wyglądać jak operatora, a więc tylko w ten sposób powłoka może przetworzyć tego testu jest traktowanie =jako operatora binarnego.

Wszystkie współczesne powłoki, a nawet większość starszych powłok, które nadal działają, są zgodne z regułami POSIX, które nakazują prawidłowe analizowanie wszystkich wyrażeń testowych o długości do 4 słów. Więc [ -z "$1" ]jest właściwym sposobem testowania jeśli $1jest pusta , a [ "$x" = "$y" ]to właściwa droga do testowania równości dwóch zmiennych.

Nawet niektóre bieżące powłoki mogą zostać pomylone z dłuższymi wyrażeniami, a kilka wyrażeń jest w rzeczywistości niejednoznacznych, więc unikaj używania operatorów -ai -odo konstruowania dłuższych testów boolowskich, a zamiast tego używaj osobnych wywołań do [oraz własnych &&i ||boolowskich operatorów powłoki .


3
To nie tylko historyczne muszle. Niektóre ksh88 oparte shna niektórych komercyjnych Uniksach nadal mają problem. Zobacz tutaj po szczegóły.
Stéphane Chazelas

To stwierdzenie jest niepoprawne: [ -z "$1" ]jest właściwym sposobem sprawdzenia, czy $1jest puste . sh -c '[ -z "$1" ]' ''; sh -c '[ -z "$1" ]'- oba zwracają 0, ale w drugim przypadku $1nie mogą być puste, ponieważ nie istnieje.
mikeserv


3

Powyższe testy spowodują również błąd, jeśli uruchomisz z „set -u” lub „set -o rzeczownik”

Bardziej stabilnym sposobem sprawdzenia pustej zmiennej byłoby użycie rozszerzenia parametrów :

MYVAR = $ {MYVAR: - „Zła wartość”}

Ta metoda działa dla tradycyjnej powłoki bourne, a także dla ksh i bash.


2
Uważam, że jest to napisane jako -> M = $ {M: - „Zła wartość”}
Gyan

0
    function isBlank {
 valueNoSpaces=$(echo "$@" | tr -d ' ')

 if [  "$valueNoSpaces" == null ] || [ -z "$valueNoSpaces" ] 
 then
       echo true ;
 else
       echo ""  ;
 fi
}

#Test
if [ $(isBlank "      ") ] 
then
    echo "isBlank \"      \" : it's blank"
else
    echo " isBlank \"      \": it is not blank"
fi

if [ $(isBlank "abc") ] 

then
    echo "isBlank \"abc\" : it's blank"
else
    echo "isBlank \"abc\" :it is not blank"
fi

if [ $(isBlank null) ] 
then
      echo "isBlank null : it's blank"
else
    echo "isBlank null : it is not blank"
fi

if [ $(isBlank "") ] 
then
    echo "isBlank \"\" : it's blank"
else
    echo "isBlank \"\" : it is not blank"
fi

#Result
isBlank "      " : it's blank

isBlank "abc" :it is not blank

isBlank null : it's blank

isBlank "" : it's blank

3
Cześć! Nie jestem pewien, jak to odpowiada na pytanie, które pyta, dlaczego używać =kontra -zteraz, w jaki sposób.
dhag
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.