Cum pot testa dacă o variabilă este goală sau conține doar spații?

Următoarea sintaxă bash verifică dacă param nu este „gol:

 [[ ! -z $param ]] 

De exemplu:

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

Fără ieșire și bine.

Dar când param este gol, cu excepția unuia (sau mai multor) caractere spațiale, atunci cazul este diferit:

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

„Eu nu sunt zero „este afișat.

Cum pot modifica testul pentru a considera variabilele care conțin doar caractere spațiale ca fiind goale?

Comentarii

  • Din man test: -z STRING - the length of STRING is zero. Dacă doriți să eliminați toate spațiile din $param, utilizați ${param// /}
  • WOW nu există o funcție simplă trim() încorporată în vreo * nix? Atât de multe hack-uri diferite pentru a realiza ceva atât de simplu …
  • @ADTC $ (sed ‘ s / ^ \ s + | \ s + $ // g ‘ < < < $ string) mi se pare suficient de simplu. De ce să reinventăm roata?
  • Pentru că ar putea fi mai strălucitoare
  • Doar menționând că [[ ! -z $param ]] este echivalent cu test ! -z $param.

Răspuns

Mai întâi, rețineți că -z test este explicit pentru:

lungimea șirului este zero

Adică, un șir care conține numai spații ar trebui nu fi adevărat sub -z, deoarece are o lungime diferită de zero.

Ce doriți este să eliminați spațiile din variabilă utilizând extinderea parametrului de înlocuire a modelului :

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

Aceasta extinde param variabilă și înlocuiește toate meciurile modelului (un singur spațiu) cu nimic, astfel încât un șir care are numai spații în el va fi extins la șir gol.


nitty-gritty a modului în care funcționează este ${var/pattern/string} înlocuiește primul cel mai lung meci din pattern cu string. Când pattern începe cu / (ca mai sus), atunci înlocuiește toate potrivirile. Deoarece înlocuirea este goală, putem omite / final și valoarea string:

$ {parametru / model / șir}

șablonul este extins pentru a produce un șablon la fel ca în expansiunea numelui de fișier. Parametrul este extins și cea mai lungă potrivire a modelului cu valoarea acestuia este înlocuită cu șir . Dacă model începe cu ‘/’, toate potrivirile din model sunt înlocuite cu șir . În mod normal, doar primul meci este înlocuit. … Dacă șir este nul, potrivirile din șablon sunt șterse și rmătorul șablon poate fi omis.

După toate acestea, ajungem cu ${param// } pentru a șterge toate spațiile.

Rețineți că, deși prezent în ksh (de unde a provenit), zsh și bash, sintaxa respectivă nu este POSIX și nu trebuie utilizat în scripturile sh.

Comentarii

  • utilizați sed au spus … doar echo variabila pe care au spus-o …
  • Hmm. Dacă este ${var/pattern/string}, atunci nu ar trebui să ‘ să fie [[ -z ${param/ /} ]] cu spațiul dintre bare oblice să fie modelul și nimic după ce să fie șirul?
  • @JesseChisholm ” Deoarece înlocuirea este goală, putem omite valoarea finală și șirul „; ” Dacă șir este nul, potrivirile șablon sunt șterse și / următorul șablon poate fi omis. ”
  • @MichaelHomer Răspunsul [[ -z "${param// }" ]] sigur arată ca pattern este gol și replacement string este un spațiu unic. AH! Îl văd acum if pattern begins with a slash Am ratat acea parte. deci modelul este / , iar șirul este lăsat și, prin urmare, gol. Mulțumesc.
  • notă bash: dacă rulează în set -o nounset (set -u), iar param nu este setat (mai degrabă decât nul sau completat de spațiu), atunci acest lucru va genera o eroare variabilă nelegată. (set + u; …..) ar scuti acest test.

Răspuns

Modul ușor a verifica dacă un șir conține doar caractere într-un set autorizat înseamnă a testa prezența caracterelor neautorizate.Astfel, în loc să testați dacă șirul conține doar spații, testați dacă șirul conține alt caracter decât spațiul. În bash, ksh sau zsh:

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

„Constă doar din spații” include cazul unei variabile goale (sau nesetate).

Poate doriți să testați orice caracter spațial. Utilizați [[ $param = *[^[:space:]]* ]] pentru a utiliza setările locale sau orice altă listă explicită de caractere spațiale pe care doriți să le testați, de ex. [[ $param = *[$" \t\n"]* ]] pentru a testa spațiul, fila sau linia nouă.

Potrivirea unui șir cu un model cu = în interiorul [[ … ]] este o extensie ksh (prezentă și în bash și zsh). În orice stil Bourne / POSIX, puteți utiliza construcția case pentru a potrivi un șir cu un model. Rețineți că modelele standard ale shell-ului folosesc ! pentru a anula un set de caractere, mai degrabă decât ^ ca în majoritatea sintaxelor expresiilor regulate.

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

Pentru a testa caracterele spațiului alb, sintaxa $"…" este specifică ksh / bash / zsh; puteți introduce aceste caractere în scriptul dvs. literalmente (rețineți că o linie nouă va trebui să fie cuprinsă între ghilimele, deoarece backslash + newline nu se extinde la nimic), sau să le generați, de exemplu

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

Comentarii

  • Acesta este aproape excelent – dar, deocamdată, nu răspunde la întrebarea așa cum a fost pusă. În prezent, vă poate spune diferența dintre o variabilă shell sau goală necompletată și una care conține doar spații. Dacă veți accepta sugestia mea, veți adăuga formularul de extindere param care nu a fost încă convertit de niciun alt răspuns care testează în mod explicit o variabilă shell pentru a fi setată – mă refer la ${var?not set} – trecând testul respectiv și supraviețuind s-ar asigura că o variabilă potrivită cu *) case va da un răspuns definitiv, de exemplu.
  • Corecție – acest fapt, de fapt, ar răspunde la întrebarea adresată inițial, dar de atunci a fost editat în așa fel încât să schimbe fundamental sensul întrebării și, prin urmare, să invalideze răspunsul dvs.
  • Aveți nevoie de [[ $param = *[!\ ]* ]] în mksh.

Răspuns

POSIXly:

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

Pentru a face diferența între blank , non-blank , gol , dezactivat :

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

[:blank:] este pentru caractere de spațiere orizontală (spațiu și filă în A SCII, dar probabil mai sunt câteva în localitatea dvs.; unele sisteme vor include spațiul neîntrerupt (acolo unde este disponibil), unele vor câștiga „t). Dacă doriți și caractere de spațiere verticală (cum ar fi linia nouă sau formularul), înlocuiți [:blank:] cu [:space:].

Comentarii

  • POSIXly este ideal, deoarece va funcționa cu (probabil mai bine) liniuță.
  • zsh pare să aibă probleme cu [![:blank:]], crește :b este modificator nevalid. În emularea sh și ksh, evenimentul de creștere nu a fost găsit pentru [
  • @cuonglm, ce ai încercat? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' este OK pentru mine. Evenimentul care nu a fost găsit ar fi decât pentru shell-uri interactive.
  • @St é phaneChazelas: Ah, corect, am încercat cu shell-uri interactive. :b modificatorul invalid este un pic ciudat.
  • @FranklinYu, pe OS / X sh este construit cu --enable-xpg-echo-default și --enable-strict-posix-default astfel încât să fie conform Unix (care implică echo '\t' afișarea unei file).

Răspuns

Singurul motiv rău pentru a scrie un script shell, în loc de un script într-un bun limbaj de script, este dacă portabilitatea extremă este o preocupare majoră. > Moștenirea /bin/sh este singurul lucru pe care îl puteți avea sigur, dar Perl, de exemplu, este mai probabil să fie disponibil pe mai multe platforme decât Bash. Prin urmare, nu scrieți niciodată scripturi shell care utilizează caracteristici care nu sunt „cu adevărat universale – și rețineți că mai mulți furnizori Unix proprietari și-au înghețat mediul shell înainte de POSIX.1-2001 .

Există un mod portabil de a face acest test, dar trebuie să utilizați tr:

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

(Valoarea implicită a $IFS, în mod convenabil, este un spațiu, o filă și o linie nouă.)

(printf builtin este el însuși foarte portabil, dar să te bazezi pe el este mult mai puțin dificil decât să afli ce variantă de echo ai.)

Comentarii

  • Că ‘ este un pic complicat.Modul obișnuit de a testa dacă un șir conține anumite caractere este cu case .
  • @Gilles Nu ‘ cred că este posibil ‘ să scrieți un case glob detectați un șir care este fie gol, fie conține numai caractere în spațiu. (Ar fi ușor cu o regexp, dar case nu face regexps. Construcția din răspunsul dvs. a câștigat ‘ nu funcționează dacă vă pasă de linii noi.)
  • Am dat spații ca exemplu în răspunsul meu, deoarece ‘ este care este întrebarea a cerut. Este ‘ la fel de ușor de testat pentru caracterele spațiului alb: case $param in *[![:space:]]*) …. Dacă doriți să testați caracterele IFS, puteți utiliza modelul *[$IFS]*.
  • @mikeserv Într-un serios script defensiv, setați explicit IFS la <space><tab><newline> la început și apoi nu îl mai atingeți niciodată. Am crezut că ‘ ar fi o distragere a atenției.
  • În ceea ce privește variabilele din tipare, cred că funcționează în toate versiunile Bourne și toate shell-urile POSIX; ar necesita cod suplimentar pentru a detecta tiparele de cazuri și pentru a dezactiva expansiunea variabilă și nu pot ‘ să mă gândesc la un motiv pentru a o face. Am câteva exemple în .profile, care a fost executat de multe obuze Bourne. Desigur, [$IFS] a câștigat ‘ să nu facă ceea ce se intenționa dacă IFS are anumite elemente non-implicite valori (goale (sau nesetate), care conțin ], începând cu ! sau ^) .

Răspuns

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 

Comentarii

  • acest lucru scapă de orice caracter de spațiu alb, nu doar de un singur spațiu, nu? mulțumesc

Răspuns

Pentru a testa dacă variabila este goală sau conține spații, puteți utiliza și acest cod:

${name:?variable is empty} 

Comentarii

  • Cred că răspunsul dvs. este votat în jos deoarece ” sau conține spații ” nu este adevărat.
  • atenție – care ucide shell-ul curent. Mai bine să-l puneți într-un (: $ {subshell?}). De asemenea – care va scrie pe stderr – probabil că doriți redirecționare. Și cel mai important care evaluează valoarea reală a variabilei ‘ dacă nu este nesetată sau nulă. Dacă există ‘ o comandă acolo, tocmai ați executat-o. Este ‘ cel mai bine să rulați testul pe :.
  • cum va ucide shell-ul. și puteți testa, de asemenea, mai întâi definiți name=aaaa apoi executați această comandă echo ${name:?variable is empty} va imprima valoarea numelui variabilei și acum executați această comandă echo ${name1:?variable is empty} se va imprima -sh: name1: variabila este goală
  • Da – echo ${name:?variable is empty} fie va evalua la $name ‘ valoarea non-nulă sau va ucide shell-ul. Deci, din același motiv, nu ‘ nu faci prompt > $randomvar și nu ar trebui să ${var?} – dacă ‘ este o comandă acolo, ‘ probabil va rula – și nu ‘ nu știu ce este. Un shell interactiv nu trebuie să iasă ‘ – motiv pentru care al tău nu ‘ t. Totuși, dacă doriți să vedeți câteva teste, există multe dintre ele aici. . Acesta nu este ‘ atât de lung …

Răspuns

Codul pe care l-ați postat [[ ! -z $param ]] && echo "I am not zero" va imprima I am not zero dacă parametrul este fie nesetat / nedefinit, fie gol (în bash, ksh și zsh).

To și tipăriți dacă parametrul conține doar spații (eliminați spațiile), POSIXly (pentru o gamă mai largă de cochilii):

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

Explicație:

  • Un ${param# … } elimină un text care conduce .
  • Textul principal este dat de: ${param%%[! ]*}
  • Care se extinde la toate spațiile dinaintea orice caracter non-space , adică toate spațiile principale.

Rezultatul final al întregii expansiuni este eliminarea tuturor spațiilor principale.

Acest rezultat extins este testat dacă are lungimea 0.

  • Dacă rezultatul este gol, atunci fie variabila a fost goală, fie
  • eliminarea spațiilor principale a făcut-o goală.

Prin urmare, dacă testul este adevărat, variabila era deja goală sau avea doar spații în ea.


Conceptul este ușor de extins la mai multe tipuri de caractere. Pentru a include, de asemenea, file, plasați o filă explicită în expresia paranteză:

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

sau utilizați o variabilă cu caracterele pe care trebuie să le eliminați:

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

sau puteți utiliza unele „expresii de clase de caractere” POSIX (gol înseamnă spațiu și filă):

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

Răspuns

Pentru a verifica dacă variabila are doar spații, inclusiv într-o variabilă multi-linie div id = „660e34d3e4”>

, încercați acest lucru:

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

Sau cu xargs:

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

Sau cu sed:

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

Răspuns

Încercați acest lucru:

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

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *