Jak mogę sprawdzić, czy zmienna jest pusta lub zawiera tylko spacje?

Poniższa składnia bash sprawdza, czy param nie jest „t pusty”:

 [[ ! -z $param ]] 

Na przykład:

param="" [[ ! -z $param ]] && echo "I am not zero" 

Brak wyjścia i wszystko w porządku.

Ale kiedy param jest puste, z wyjątkiem jednego (lub więcej) znaków spacji, wtedy wielkość liter jest inna:

param=" " # one space [[ ! -z $param ]] && echo "I am not zero" 

„Nie jestem zero ”.

Jak mogę zmienić test, aby uwzględniał zmienne zawierające tylko spacje jako puste?

Komentarze

  • Z man test: -z STRING - the length of STRING is zero. Jeśli chcesz usunąć wszystkie spacje w $param, użyj ${param// /}
  • WOW nie ma prostej funkcji trim() wbudowanej w w ogóle jakieś * nix? Tak wiele różnych sposobów na osiągnięcie czegoś tak prostego …
  • @ADTC $ (sed ' s / ^ \ s + | \ s + $ // g ' < < < $ string) wydaje mi się dość proste. Po co odkrywać koło na nowo?
  • Ponieważ mogłoby być bardziej błyszczące
  • Wystarczy zauważyć, że [[ ! -z $param ]] jest równoważne z test ! -z $param.

Odpowiedź

Po pierwsze, zwróć uwagę, że -z test jest wyraźnie przeznaczony dla:

długość łańcucha wynosi zero

Oznacza to, że ciąg zawierający tylko spacje powinien a nie będzie prawdziwe pod -z, ponieważ ma niezerową długość.

To, czego chcesz, to usunięcie spacji ze zmiennej za pomocą rozwinięcie parametru zastępującego wzorzec :

[[ -z "${param// }" ]] 

To rozszerza param i zastępuje wszystkie dopasowania wzorca (pojedyncza spacja) niczym, więc ciąg zawierający tylko spacje zostanie rozwinięty do pusty ciąg.


najważniejsze, jak to działa , to ${var/pattern/string} zamienia pierwsze najdłuższe dopasowanie pattern na string. Kiedy pattern zaczyna się od / (jak wyżej), zastępuje wszystkie dopasowania. Ponieważ zamiennik jest pusty, możemy pominąć ostatnią wartość / i string:

$ {parametr / wzorzec / ciąg}

wzorzec jest rozwijany w celu utworzenia wzorca, tak jak przy rozwijaniu nazw plików. Parametr jest rozwijany, a najdłuższe dopasowanie wzorca do jego wartości jest zastępowane ciągiem . Jeśli wzorzec zaczyna się od „/”, wszystkie dopasowania wzorca są zastępowane ciągiem . Zwykle zastępowane jest tylko pierwsze dopasowanie. … Jeśli ciąg ma wartość null, dopasowania wzorca są usuwane, a / następujący wzorzec może zostać pominięty.

Po tym wszystkim otrzymujemy ${param// }, aby usunąć wszystkie spacje.

Pamiętaj, że obecny w ksh (skąd pochodzi), zsh i bash, ta składnia nie jest POSIX i nie powinien być używany w sh skryptach.

Komentarze

  • użyj sed powiedzieli … tylko echo zmienna, którą powiedzieli …
  • Hmm. Jeśli to ${var/pattern/string}, to nie powinno być ' t, powinno to być [[ -z ${param/ /} ]] ze spacją między ukośnikami być wzorcem, a nic po nim ciągiem?
  • @JesseChisholm ” Ponieważ zamiennik jest pusty, możemy pominąć końcowe / i wartość ciągu „; ” Jeśli ciąg ma wartość null, dopasowania wzorca są usuwane i / po wzorcu może zostać pominięto. ”
  • @MichaelHomer Odpowiedź [[ -z "${param// }" ]] z pewnością wygląda jak pattern jest pusty, a replacement string to pojedyncza spacja. AH! Teraz to widzę if pattern begins with a slash Brakowało mi tej części. więc wzorzec to / , a ciąg jest pozostawiony i dlatego pusty. Dzięki.
  • uwaga basha: jeśli działa w ustawieniu -o rzeczownik (set -u), a parametr jest nieustawiony (a nie pusty lub wypełniony spacjami), to wygeneruje błąd niezwiązanej zmiennej. (set + u; …..) wykluczy ten test.

Odpowiedź

Prosty sposób sprawdzenie, czy ciąg zawiera tylko znaki z autoryzowanego zestawu, jest testem na obecność nieautoryzowanych znaków.Dlatego zamiast sprawdzać, czy ciąg zawiera tylko spacje, sprawdź, czy ciąg zawiera znak inny niż spacja. W bash, ksh lub zsh:

if [[ $param = *[!\ ]* ]]; then echo "\$param contains characters other than space" else echo "\$param consists of spaces only" fi 

„Składa się tylko ze spacji” obejmuje przypadek pustej (lub nieustawionej) zmiennej.

Możesz chcieć sprawdzić, czy nie ma żadnych białych znaków. Użyj [[ $param = *[^[:space:]]* ]], aby użyć ustawień regionalnych lub dowolnej jawnej listy białych znaków, które chcesz przetestować, np. [[ $param = *[$" \t\n"]* ]] do testowania spacji, tabulacji lub nowej linii.

Dopasowanie ciągu do wzorca z = wewnątrz [[ … ]] to rozszerzenie ksh (obecne także w bash i zsh). W każdym stylu Bourne / POSIX można użyć konstrukcji case w celu dopasowania ciągu do wzorca. Zwróć uwagę, że standardowe wzorce powłoki używają ! do zanegowania zestawu znaków, a nie ^, jak w większości składni wyrażeń regularnych.

case "$param" in *[!\ ]*) echo "\$param contains characters other than space";; *) echo "\$param consists of spaces only";; esac 

Aby sprawdzić, czy nie ma białych znaków, składnia $"…" jest specyficzna dla ksh / bash / zsh; możesz wstawić te znaki w swoim skrypcie dosłownie (pamiętaj, że znak nowej linii będzie musiał znajdować się w cudzysłowie, ponieważ ukośnik odwrotny + znak nowej linii oznacza nic) lub wygeneruj je, np.

whitespace=$(printf "\n\t ") case "$param" in *[!$whitespace]*) echo "\$param contains non-whitespace characters";; *) echo "\$param consists of whitespace only";; esac 

Komentarze

  • To jest prawie doskonałe – ale jak dotąd nie odpowiada na zadane pytanie. Obecnie jest w stanie wskazać różnicę między nieustawioną lub pustą zmienną powłoki a taką, która zawiera tylko spacje. Jeśli zaakceptujesz moją sugestię, dodasz formularz rozwijania parametrów, który nie został jeszcze poznany przez żadną inną odpowiedź, która wyraźnie testuje zmienną powłoki pod kątem ustawienia – mam na myśli ${var?not set} – zaliczenie tego testu i przetrwanie zapewni, że zmienna dopasowana do Twojego *) case wpłynie na przykład na ostateczną odpowiedź.
  • Poprawka – w rzeczywistości oznaczałoby odpowiedź na pierwotnie zadane pytanie, ale od tego czasu zostało zredagowane w taki sposób, że zasadniczo zmienia znaczenie pytania, a tym samym unieważnia twoją odpowiedź.
  • Potrzebujesz [[ $param = *[!\ ]* ]] w mksh.

Odpowiedź

POSIXly:

case $var in (*[![:blank:]]*) echo "$var contains non blank";; (*) echo "$var contains only blanks or is empty or unset" esac 

Aby odróżnić puste , niepuste , pusty , nieustawiony :

case ${var+x$var} in (x) echo empty;; ("") echo unset;; (x*[![:blank:]]*) echo non-blank;; (*) echo blank esac 

[:blank:] służy do znaków odstępów poziomych (spacja i tabulator w A SCII, ale prawdopodobnie jest ich kilka więcej w twoim locale; niektóre systemy będą zawierać nierozdzielającą spację (jeśli jest dostępna), inne nie będą miały „t”. Jeśli chcesz, aby również znaki odstępów pionowych (np. nowa linia lub wysuw strony), zamień [:blank:] z [:space:].

Komentarze

  • POSIXly jest idealne, ponieważ będzie działać z (prawdopodobnie lepiej) myślnik.
  • zsh wydaje się mieć problem z [![:blank:]], podnosi :b jest nieprawidłowym modyfikatorem. W emulacji sh i ksh zgłasza zdarzenie nie znalezione dla [
  • @cuonglm, czego próbowałeś? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' jest dla mnie w porządku. Nie znaleziono zdarzenia tylko dla powłok interaktywnych.
  • @St é phaneChazelas: Ach, tak, próbowałem z powłokami interaktywnymi. :b modyfikator jest trochę dziwny.
  • @FranklinYu, na OS / X sh to zbudowany z --enable-xpg-echo-default i --enable-strict-posix-default w celu zapewnienia zgodności z Uniksem (co obejmuje echo '\t' wypisywanie karty).

Odpowiedź

Jedyny pozostały powód do napisania skrypt powłoki, zamiast skryptu w dobrym języku skryptowym, oznacza, że ekstremalna przenośność jest nadrzędnym problemem. Starsza wersja /bin/sh to jedyna rzecz, której możesz być pewien, ale na przykład Perl jest bardziej dostępny na wielu platformach niż Bash. Dlatego nigdy nie pisz skryptów powłoki, które używają funkcji, które nie są prawdziwie uniwersalne – i pamiętaj, że kilku firmowych dostawców Uniksa zamroziło swoje środowisko powłoki przed POSIX.1-2001 .

Istnieje przenośny sposób wykonania tego testu, ale musisz użyć tr:

[ "x`printf "%s" "$var" | tr -d "$IFS"`" = x ] 

(Domyślną wartością $IFS jest spacja, tabulator i nowa linia.)

(printf jest samo w sobie przenośny, ale poleganie na nim jest znacznie mniej kłopotliwe niż ustalenie, który wariant echo posiadasz.)

Komentarze

  • To ' jest nieco zagmatwane.Zwykły przenośny sposób sprawdzania, czy ciąg zawiera określone znaki, to z case .
  • @Gilles Nie ' nie sądzę, że ' można napisać case glob do wykrywa ciąg, który jest pusty lub zawiera tylko białe znaki. (Byłoby łatwo z wyrażeniem regularnym, ale case nie ' nie robi wyrażeń regularnych. Konstrukcja w Twojej odpowiedzi wygrała ' nie działa, jeśli zależy ci na nowych wierszach.)
  • Podałem spacje jako przykład w mojej odpowiedzi, ponieważ ' oto jest pytanie spytany o. ' równie łatwo jest sprawdzić, czy nie ma białych znaków: case $param in *[![:space:]]*) …. Jeśli chcesz przetestować IFS znaków, możesz użyć wzorca *[$IFS]*.
  • @mikeserv W naprawdę poważnie skryptem obronnym, na początku jawnie ustawiłeś IFS na <space><tab><newline> i nigdy więcej go nie dotykasz. Myślałem, że ' może rozpraszać uwagę.
  • Jeśli chodzi o zmienne we wzorcach, myślę, że działa to we wszystkich wersjach Bourne i wszystkich powłokach POSIX; wymagałoby to dodatkowego kodu do wykrywania wzorców wielkości liter i wyłączania rozwijania zmiennych, a nie mogę ' wymyślić powodu, aby to zrobić. Mam kilka jego instancji w moim .profile, który był wykonywany przez wiele powłok Bournea. Oczywiście [$IFS] wygrał ' Nie zrobię tego, co było zamierzone, jeśli IFS ma pewne wartości inne niż domyślne wartości (puste (lub nieustawione), zawierające ], zaczynające się od ! lub ^) .

Odpowiedź

if [[ -n "${variable_name/[ ]*\n/}" ]] then #execute if the the variable is not empty and contains non space characters else #execute if the variable is empty or contains only spaces fi 

Komentarze

  • to usuwa wszelkie białe znaki, a nie tylko pojedynczą spację, prawda? dzięki

Odpowiedź

Aby sprawdzić, czy zmienna jest pusta lub zawiera spacje, możesz również użyć tego kodu:

${name:?variable is empty} 

Komentarze

  • Myślę, że Twoja odpowiedź została odrzucona, ponieważ ” lub zawierają spacje ” nie jest prawdą.
  • uważaj – to zabija bieżącą powłokę. Lepiej umieścić to w (: $ {podpowłoka?}). Również – to napisze na stderr – prawdopodobnie chcesz przekierować. I najważniejsze , które zwraca wartość zmiennej ' do rzeczywistej wartości, jeśli nie jest nieustawiona lub zerowa. Jeśli jest tam ' polecenie, po prostu je uruchomiłeś. Najlepiej jest ' uruchomić ten test na :.
  • jak zabije powłokę. i możesz to również przetestować, najpierw zdefiniuj name=aaaa, a następnie uruchom to polecenie echo ${name:?variable is empty} wypisze wartość nazwy zmiennej i teraz uruchomi to polecenie echo ${name1:?variable is empty} wypisze -sh: name1: zmienna jest pusta
  • Tak – echo ${name:?variable is empty} zwróci wartość $name ' jako wartość różną od null lub zabije powłokę. Dlatego z tego samego powodu nie ' nie należy prompt > $randomvar ani ${var?} – jeśli tam ' jest tam polecenie, ' prawdopodobnie będzie działać – a Ty nie ' nie wiem, co to jest. Powłoka interaktywna nie ' nie musi się kończyć – dlatego Twoja nie ' t. Mimo to, jeśli chcesz zobaczyć kilka testów, jest ich dużo tutaj . Ten nie jest ' tak długi …

Odpowiedź

Kod, który opublikowałeś [[ ! -z $param ]] && echo "I am not zero", spowoduje wydrukowanie I am not zero, jeśli parametr jest nieustawiony / niezdefiniowany lub pusty (w bash, ksh i zsh).

To także wypisz jeśli parametr zawiera tylko spacje (usuń spacje), POSIXly (dla szerszego zakresu powłok):

 [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty" 

Wyjaśnienie:

  • ${param# … } usuwa początkowy tekst .
  • Ten początkowy tekst to: ${param%%[! ]*}
  • , który rozwija się do wszystkich spacji przed dowolny inny niż spacja znak, tj. Wszystkie początkowe spacje.

Efektem końcowym całego rozwinięcia jest usunięcie wszystkich wiodących spacji.

Ten rozszerzony wynik jest sprawdzany, jeśli ma długość 0.

  • Jeśli wynik jest pusty, to albo zmienna była pusta, albo
  • usuwając początkowe spacje opróżnił go.

Dlatego jeśli test jest prawdziwy, zmienna była już pusta lub zawierała tylko spacje.


Koncepcja jest łatwa do rozszerzenia na więcej typy znaków. Aby uwzględnić również tabulatory, umieść wyraźną tabulator wewnątrz wyrażenia w nawiasach:

 [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty" 

lub użyj zmiennej ze znakami, które chcesz usunąć:

 var=$" \t" # in ksh, bash, zsh [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty" 

lub możesz użyć jakiegoś POSIX „wyrażenia klasy znaków” (puste oznacza spację i tabulator):

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty" 

Odpowiedź

Aby sprawdzić, czy zmienna ma tylko spacje, w tym w zmiennej wieloliniowej , spróbuj tego:

[[ $var = *[$" \t\n"]* ]] 

Lub z xargs:

[[ -z $(echo $var | xargs) ]] 

Lub sedem:

[[ -z $(sed "/^$/d" <<< $var) ]] 

Odpowiedź

Spróbuj tego:

$ [[ -z \`echo $n\` ]] && echo zero zero 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *