Jak mohu otestovat, zda je proměnná prázdná nebo obsahuje pouze mezery?

Následující bash syntaxe ověřuje, zda param není prázdný:

 [[ ! -z $param ]] 

Například:

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

Žádný výstup a jeho pokuta.

Ale když param je prázdný s výjimkou jednoho (nebo více) mezer, pak je případ jiný:

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

„Nejsem nula „je na výstupu.

Jak mohu změnit test tak, aby považoval proměnné, které obsahují pouze mezery, za prázdné?

Komentáře

  • From man test: -z STRING - the length of STRING is zero. Pokud chcete odstranit všechny mezery v $param, použijte ${param// /}
  • WOW neexistuje jednoduchá funkce trim() jakýkoli * nix vůbec? Tolik různých hacků k dosažení něčeho tak jednoduchého …
  • @ADTC $ (sed ‚ s / ^ \ s + | \ s + $ // g ‚ < < < $ string) se mi zdá dost jednoduchý. Proč znovu objevovat kolo?
  • Protože by to mohlo být lesklejší
  • Jen poznamenám, že [[ ! -z $param ]] je ekvivalentní s test ! -z $param.

Odpověď

Nejprve si všimněte, že -z test je výslovně určen pro:

délka řetězce je nula

To znamená, že řetězec obsahující pouze mezery by neměl být pravdivý pod -z, protože má nenulovou délku.

To, co chcete, je odstranit mezery z proměnné pomocí rozšíření parametrů nahrazení vzoru :

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

Tím se rozšíří param a nahradí všechny shody vzoru (jedna mezera) ničím, takže řetězec, který obsahuje pouze mezery, bude rozbalen na prázdný řetězec.


hloupost toho, jak to funguje , je ${var/pattern/string} nahrazuje první nejdelší shodu pattern za string. Když pattern začíná / (jak je uvedeno výše), nahradí všechny shody. Protože náhrada je prázdná, můžeme vynechat konečnou / a string hodnotu:

$ {parametr / vzor / řetězec}

Vzor se rozbalí a vytvoří vzor stejně jako v rozšíření názvu souboru. Parametr se rozbalí a nejdelší shoda vzoru s jeho hodnotou se nahradí řetězcem . Pokud vzor začíná na „/“, všechny shody vzoru jsou nahrazeny řetězcem . Normálně je nahrazen pouze první zápas. … Pokud řetězec má hodnotu null, budou odstraněny shody vzoru a / následující vzor může být vynechán.

Po tom všem skončíme s ${param// } smazáním všech mezer.

Pamatujte však, že přítomné v ksh (odkud pochází), zsh a bash, tato syntaxe není POSIX a neměl by se používat ve sh skriptech.

Komentáře

  • použít sed řekli … jen echo proměnnou, kterou řekli …
  • Hmm. Pokud je to ${var/pattern/string}, nemělo by to být ‚ t [[ -z ${param/ /} ]] s mezerou mezi lomítky být vzorem a nic poté, co být řetězcem?
  • @JesseChisholm “ Protože náhrada je prázdná, můžeme vynechat konečnou / a hodnotu řetězce „; “ Pokud je řetězec null, budou odstraněny shody vzoru a může být / následující vzor vynecháno. “
  • @MichaelHomer Odpověď [[ -z "${param// }" ]] určitě vypadá jako pattern je prázdný a replacement string je jeden prostor. AH! Vidím to nyní if pattern begins with a slash Tuto část jsem zmeškal. vzor je tedy / a řetězec je vynechán, a proto je prázdný. Díky.
  • poznámka bash: pokud běží v set -o nounset (set -u) a param je unset (spíše než null nebo mezera), vygeneruje to chybu nevázané proměnné. (set + u; …..) by tento test vyňal.

Odpověď

Snadný způsob zkontrolovat, zda řetězec obsahuje pouze znaky v autorizované sadě, je otestovat přítomnost neautorizovaných znaků.Takže místo testování, zda řetězec obsahuje pouze mezery, otestujte, zda řetězec obsahuje jiný znak než mezeru. V bash, ksh nebo zsh:

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

„Skládá se pouze z mezer“ zahrnuje případ prázdné (nebo zrušené) proměnné.

Možná budete chtít otestovat jakýkoli prázdný znak. Pomocí [[ $param = *[^[:space:]]* ]] použijte nastavení národního prostředí nebo jakýkoli explicitní seznam mezer, které chcete otestovat, např. [[ $param = *[$" \t\n"]* ]] k testování prostoru, tabulátoru nebo nového řádku.

Porovnání řetězce se vzorem s = uvnitř [[ … ]] je přípona ksh (také přítomná v bash a zsh). V jakémkoli stylu Bourne / POSIX můžete použít konstrukci case k porovnání řetězce se vzorem. Všimněte si, že standardní vzory prostředí používají ! k negaci znakové sady, místo ^ jako ve většině syntaxí regulárních výrazů.

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

Chcete-li otestovat prázdné znaky, je syntaxe $"…" specifická pro ksh / bash / zsh; můžete tyto znaky vložit do svého skriptu doslovně (všimněte si, že nový řádek bude muset být v uvozovkách, protože zpětné lomítko + nový řádek se rozšiřuje na nic), nebo je generovat, např.

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

Komentáře

  • To je téměř vynikající – zatím však na otázku neodpovídá tak, jak byla položena. V současné době vám může říci rozdíl mezi zrušenou nebo prázdnou proměnnou shellu a jednou, která obsahuje pouze mezery. Pokud přijmete můj návrh, přidáte formulář pro rozšíření parametrů, který ještě nebyl převeden jinou odpovědí, která explicitně testuje proměnnou prostředí pro nastavení – myslím ${var?not set} – absolvování tohoto testu a přežití zajistí, že proměnná odpovídající vašemu *) case bude mít například konečnou odpověď.
  • Oprava – to by ve skutečnosti odpovědělo na původně položenou otázku, ale od té doby byla upravena takovým způsobem, že zásadně mění význam otázky, a proto zneplatňuje vaši odpověď.
  • Potřebujete [[ $param = *[!\ ]* ]] v mksh.

Odpovědět

POSIXly:

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

Rozlišovat mezi prázdnými , neprázdnými , prázdný , zrušit :

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

[:blank:] je pro vodorovné mezery mezi znaky (mezera a karta v A SCII, ale ve vašem národním prostředí je pravděpodobně několik dalších; některé systémy budou obsahovat nerozbitný prostor (pokud je k dispozici), některé nebudou „t“. Pokud chcete také znaky se svislými mezerami (například nový řádek nebo form-feed), nahraďte [:blank:] s [:space:].

Komentáře

  • POSIXly je ideální, protože bude fungovat s (pravděpodobně lepšími) pomlčka.
  • zsh má zřejmě problém s [![:blank:]], zvyšuje :b je neplatný modifikátor. V emulaci sh a ksh vyvolá událost, která nebyla nalezena pro [
  • @cuonglm, co jste vyzkoušeli? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' je pro mě v pořádku. Nenalezená událost by byla pouze pro interaktivní skořápky.
  • @St é phaneChazelas: Aha, zkusil jsem to s interaktivními mušlemi. :b neplatný modifikátor je trochu divný.
  • @FranklinYu, na OS / X sh je postavený s --enable-xpg-echo-default a --enable-strict-posix-default tak, aby vyhovoval Unixu (což zahrnuje echo '\t' výstup na kartu).

Odpověď

Jediný zbývající důvod k psaní shell skript, místo skriptu ve dobrém skriptovacím jazyce, je, pokud převažuje extrémní přenositelnost. Starší /bin/sh je jediná věc, kterou si můžete být jisti, že máte, ale například Perl je častěji pravděpodobně dostupný napříč platformami než Bash. Proto nikdy nepište shell skripty, které používají funkce, které nejsou skutečně univerzální – a mějte na paměti, že několik vlastních prodejců Unixu zmrazilo jejich prostředí prostředí před POSIX.1-2001 .

Existuje tento přenosný způsob provedení tohoto testu, ale musíte použít tr:

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

(Výchozí hodnota $IFS je pohodlně mezera, karta a nový řádek.)

(printf builtin je sám o sobě skvostně přenosný, ale spoléhat se na něj je mnohem méně potíží než zjišťovat, kterou variantu echo máte.)

Komentáře

  • To je ‚ spletité.Obvyklým přenosným způsobem, jak otestovat, zda řetězec obsahuje určité znaky, je s case .
  • @Gilles Nemyslím si ‚ že ‚ je možné napsat case glob do detekovat řetězec, který je buď prázdný, nebo obsahuje pouze mezery. (S regexpem by to bylo snadné, ale case nedělá ‚ regexps. Konstrukt ve vaší odpovědi nevyhrál ‚ nefunguje, pokud vám záleží na nových řádcích.)
  • V odpovědi jsem uvedl mezery jako příklad, protože to je otázka ‚ požádal o. Stejně snadné je ‚ otestovat prázdné znaky: case $param in *[![:space:]]*) …. Pokud chcete otestovat IFS znaků, můžete použít vzor *[$IFS]*.
  • @mikeserv Opravdu vážně obranný skript, na začátku explicitně nastavíte IFS na <space><tab><newline> a už se ho nikdy nedotknete. Myslel jsem, že ‚ d bude odvádět pozornost.
  • Co se týče proměnných ve vzorcích, myslím, že to funguje ve všech verzích Bourne a ve všech skořápkách POSIX; vyžadovalo by to další kód pro detekci vzorů případů a vypnutí expanze proměnných a nemohu ‚ vymyslet důvod, proč to udělat. Mám několik instancí ve svém .profile, který byl proveden mnoha Bourneovými granáty. Samozřejmě [$IFS] nebude ‚ dělat to, co bylo zamýšleno, pokud IFS má určité jiné než výchozí hodnoty (prázdné (nebo zrušené), obsahující ], začínající ! nebo ^) .

Odpověď

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 

Komentáře

  • tím se zbavíte jakéhokoli znaku prázdného místa, nejen jednoho mezery, že? děkuji

odpověď

Pro testování, zda je proměnná prázdná nebo obsahuje mezery, můžete také použít tento kód:

${name:?variable is empty} 

Komentáře

  • Myslím, že vaše odpověď je odmítnuta, protože “ nebo obsahovat mezery “ není pravda.
  • buďte opatrní – to zabije aktuální shell. Lepší je dát to do (: $ {subshell?}). Také – to zapíše stderr – pravděpodobně budete chtít přesměrovat. A nejdůležitější , která se vyhodnotí na skutečnou hodnotu proměnné ‚, pokud není nastavená nebo null. Pokud je tam ‚ příkaz, spustili jste ho. ‚ Nejlepší je spustit tento test na :.
  • jak zabije shell. a můžete to také otestovat, nejprve definujte name=aaaa a poté spusťte tento příkaz echo ${name:?variable is empty} vypíše hodnotu názvu proměnné a nyní spusťte tento příkaz echo ${name1:?variable is empty} vytiskne -sh: name1: proměnná je prázdná
  • ano – echo ${name:?variable is empty} buď vyhodnotí na $name ‚ nenulovou hodnotu nebo zabije shell. Ze stejného důvodu tedy ‚ t prompt > $randomvar neměli byste ${var?} – pokud tam je ‚ sa příkaz, ten ‚ pravděpodobně běží – a vy ‚ nevím, co to je. Interaktivní prostředí nemusí ‚ opustit – proto ten váš ‚ t. Pokud si přesto chcete prohlédnout některé testy, je jich zde spousta. Tento není ‚ tak dlouho …

Odpověď

Kód, který jste zveřejnili [[ ! -z $param ]] && echo "I am not zero" vytiskne I am not zero pokud parametr je buď nenastavený / nedefinovaný, nebo prázdný (v bash, ksh a zsh).

Do také tisknout, pokud parametr obsahuje pouze mezery (odstranit mezery), POSIXly (pro širší rozsah skořápek):

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

Vysvětlení:

  • A ${param# … } odebere úvodní text.
  • Tento úvodní text je dán: ${param%%[! ]*}
  • který se rozšíří na všechny mezery před libovolný neprostorový znak, tj. Všechny úvodní mezery.

Konečným výsledkem celé expanze je odstranění všech předních mezer.

Tento rozšířený výsledek se testuje, pokud má délku 0.

  • Pokud je výsledek prázdný, pak byla buď proměnná prázdná, nebo
  • odstranění úvodních mezer udělal to prázdné.

Proto je-li test pravdivý, byla proměnná buď prázdná, nebo měla uvnitř pouze mezery.


Koncept lze snadno rozšířit na více typy znaků. Chcete-li zahrnout také karty, vložte explicitní kartu do výrazu závorky:

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

nebo použijte proměnnou se znaky, které potřebujete odstranit:

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

nebo můžete použít nějaký POSIX „výraz třídy znaků“ (prázdné znamená mezeru a tabulátor):

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

Odpověď

Chcete-li zkontrolovat, zda má proměnná pouze mezery, včetně víceřádkové proměnné , zkuste toto:

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

Nebo s xargs:

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

Nebo se sed:

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

Odpověď

Zkuste toto:

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

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *