Hoe kan ik testen of een variabele leeg is of alleen spaties bevat?

De volgende bash-syntaxis verifieert of param niet “t leeg is:

 [[ ! -z $param ]] 

Bijvoorbeeld:

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

Geen output en het is prima.

Maar wanneer param is leeg op één (of meer) spatie-tekens na, dan is het hoofdlettergebruik anders:

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

“Ik ben niet zero “is output.

Hoe kan ik de test veranderen om variabelen die alleen spaties bevatten als leeg te beschouwen?

Reacties

  • Van man test: -z STRING - the length of STRING is zero. Als je alle spaties in $param wilt verwijderen, gebruik ${param// /}
  • WOW er is geen simpele trim() functie ingebouwd in überhaupt een * nix? Zoveel verschillende hacks om zoiets eenvoudigs te bereiken …
  • @ADTC $ (sed ‘ s / ^ \ s + | \ s + $ // g ‘ < < < $ string) lijkt mij eenvoudig genoeg. Waarom het wiel opnieuw uitvinden?
  • Omdat het glanzender zou kunnen zijn
  • Alleen opmerken dat [[ ! -z $param ]] gelijk is aan test ! -z $param.

Antwoord

Merk allereerst op dat de -z test is expliciet voor:

de lengte van de string is nul

Dat wil zeggen, een string met alleen spaties mag niet waar zijn onder -z, omdat het een lengte heeft die niet nul is.

Wat je wilt is om de spaties uit de variabele te verwijderen met behulp van de uitbreiding patroonvervangende parameter :

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

Hiermee wordt de param variabele en vervangt alle overeenkomsten van het patroon (een enkele spatie) door niets, dus een string die alleen spaties bevat, wordt uitgebreid naar een lege string.


De kern van hoe dat werkt is dat ${var/pattern/string} vervangt de eerste langste overeenkomst van pattern door string. Wanneer pattern begint met / (zoals hierboven), dan vervangt het alle overeenkomsten. Omdat de vervanging leeg is, kunnen we de laatste / en de string waarde weglaten:

$ {parameter / patroon / string}

Het patroon wordt uitgebreid om een patroon te produceren, net als bij het uitbreiden van bestandsnamen. Parameter wordt uitgebreid en de langste overeenkomst van patroon met zijn waarde wordt vervangen door string . Als patroon begint met ‘/’, worden alle overeenkomsten van patroon vervangen door string . Normaal gesproken wordt alleen de eerste match vervangen. … Als string null is, worden overeenkomsten van patroon verwijderd en kan het / volgende patroon worden weggelaten.

Na dat alles eindigen we met ${param// } om alle spaties te verwijderen.

aanwezig in ksh (waar het vandaan komt), zsh en bash, is die syntaxis niet POSIX en mag niet worden gebruikt in sh scripts.

Reacties

  • gebruik sed ze zeiden … gewoon echo de variabele die ze zeiden …
  • Hmm. Als het ${var/pattern/string} is, zou het ‘ t [[ -z ${param/ /} ]] moeten zijn met de spatie tussen de schuine strepen om het patroon te zijn en niets daarna om de string te zijn?
  • @JesseChisholm ” Omdat de vervanging leeg is, kunnen we de laatste / en de stringwaarde weglaten “; ” Als string null is, worden overeenkomsten van patroon verwijderd en kan het / volgende patroon worden weggelaten. ”
  • @MichaelHomer Het antwoord [[ -z "${param// }" ]] lijkt zeker op de pattern is leeg en de replacement string is een enkele spatie. AH! Ik zie het nu if pattern begins with a slash Ik heb dat deel gemist. dus het patroon is / en de string is weggelaten en daarom leeg. Bedankt.
  • bash opmerking: als het draait in set -o nounset (set -u), en param is niet ingesteld (in plaats van null of spatie gevuld), dan zal dit een ongebonden variabelefout genereren. (set + u; …..) zou deze test vrijstellen.

Antwoord

De gemakkelijke manier om te controleren of een string alleen karakters bevat in een geautoriseerde set is om te testen op de aanwezigheid van niet geautoriseerde karakters.Dus in plaats van te testen of de string alleen spaties bevat, test je of de string een ander karakter dan spatie bevat. In bash, ksh of zsh:

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

“Bestaat alleen uit spaties” omvat het geval van een lege (of niet-ingestelde) variabele.

Misschien wilt u op elk witruimteteken testen. Gebruik [[ $param = *[^[:space:]]* ]] om locale instellingen te gebruiken, of welke expliciete lijst met witruimtetekens je ook wilt testen, bijv. [[ $param = *[$" \t\n"]* ]] om te testen op spatie, tab of nieuwe regel.

Een string matchen met een patroon met = binnen [[ … ]] is een ksh-extensie (ook aanwezig in bash en zsh). In elke Bourne / POSIX-stijl kunt u de case -constructie gebruiken om een string te vergelijken met een patroon. Merk op dat standaard shell-patronen ! gebruiken om een karakterset te negeren, in plaats van ^ zoals in de meeste reguliere expressiesyntaxen.

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

Om te testen op witruimtetekens, is de $"…" syntaxis specifiek voor ksh / bash / zsh; u kunt deze tekens letterlijk in uw script invoegen (merk op dat een nieuwe regel tussen aanhalingstekens moet staan, aangezien backslash + nieuwe regel naar niets wordt uitgebreid), of ze genereren, bijvoorbeeld

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

Reacties

  • Dit is bijna uitstekend – maar tot nu toe geeft het geen antwoord op de gestelde vraag. Het kan je momenteel het verschil vertellen tussen een niet-ingestelde of lege shell-variabele en een die alleen spaties bevat. Als je mijn suggestie accepteert, voeg je het param-uitbreidingsformulier toe dat nog niet is geconvergeerd door een ander antwoord dat expliciet test of een shell-variabele is ingesteld – ik bedoel ${var?not set} – die test doorstaan en overleven zou ervoor zorgen dat een variabele die overeenkomt met uw *) case bijvoorbeeld een definitief antwoord zou hebben.
  • Correctie – dit zou in feite de oorspronkelijk gestelde vraag beantwoorden, maar het is sindsdien zodanig bewerkt dat het de betekenis van de vraag fundamenteel verandert en daarom je antwoord ongeldig maakt.
  • Je hebt [[ $param = *[!\ ]* ]] nodig in mksh.

Antwoord

POSIXly:

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

Om onderscheid te maken tussen blanco , niet-blanco , leeg , uitgeschakeld :

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

[:blank:] is voor tekens met horizontale afstand (spatie en tab in A SCII, maar er zijn er waarschijnlijk nog een paar in uw omgeving; sommige systemen bevatten de niet-afbrekende spatie (indien beschikbaar), andere niet. Als u ook tekens met verticale spaties wilt (zoals nieuwe regel of form-feed), vervangt u [:blank:] met [:space:].

Reacties

  • POSIXly is ideaal omdat het zal werken met de (aantoonbaar betere) streepje.
  • zsh lijkt een probleem te hebben met [![:blank:]], het verhoogt :b is een ongeldige modifier. In sh en ksh emuleren, wordt gebeurtenis niet gevonden voor [
  • @cuonglm, wat heb je geprobeerd? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' is oké voor mij. De gebeurtenis die niet wordt gevonden, is alleen voor interactieve shells.
  • @St é phaneChazelas: Ah, ja, ik heb het geprobeerd met interactieve shells. De :b ongeldige modifier is een beetje vreemd.
  • @FranklinYu, op OS / X is sh gebouwd met --enable-xpg-echo-default en --enable-strict-posix-default om Unix-compatibel te zijn (waarbij echo '\t' uitvoer van een tabblad).

Antwoord

De enige overgebleven reden om te schrijven een shell-script, in plaats van een script in een goede scripttaal, is als extreme draagbaarheid een doorslaggevende zorg is. De erfenis /bin/sh is het enige waarvan je zeker kunt zijn dat je het hebt, maar Perl is bijvoorbeeld meer waarschijnlijk cross-platform beschikbaar dan Bash. Schrijf daarom nooit shellscripts die functies gebruiken die “niet echt universeel zijn – en onthoud dat verschillende eigen Unix-leveranciers hun shell-omgeving hebben bevroren voorafgaand aan POSIX.1-2001 .

Er is een draagbare manier om deze test uit te voeren, maar je moet tr gebruiken:

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

(De standaardwaarde van $IFS is handig een spatie, een tab en een nieuwe regel.)

(De printf ingebouwd is zelf vlekkerig draagbaar, maar erop vertrouwen is veel minder gedoe dan uitzoeken welke variant van echo je hebt.)

Opmerkingen

  • Dat ‘ is een beetje ingewikkeld.De gebruikelijke draagbare manier om te testen of een string bepaalde karakters bevat, is met case .
  • @Gilles Ik ‘ denk niet dat het ‘ mogelijk is om een case glob te schrijven naar detecteer een string die ofwel leeg is, of alleen spaties bevat. (Het zou gemakkelijk zijn met een regexp, maar case doet ‘ geen regexps. De constructie in je antwoord won ‘ werkt niet als je om nieuwe regels geeft.)
  • Ik gaf spaties als voorbeeld in mijn antwoord omdat ‘ is wat de vraag is gevraagd om. Het ‘ is even gemakkelijk te testen op witruimtetekens: case $param in *[![:space:]]*) …. Als je op IFS tekens wilt testen, kun je het patroon *[$IFS]* gebruiken.
  • @mikeserv In een echt serieus defensief script, je stelt IFS expliciet in op <space><tab><newline> aan het begin en raakt het daarna nooit meer aan. Ik dacht dat ‘ een afleiding zou zijn.
  • Wat betreft variabelen in patronen, denk ik dat dit werkt in alle Bourne-versies en alle POSIX-shells; het zou extra code nodig hebben om casuspatronen te detecteren en variabele uitbreiding uit te schakelen en ik kan ‘ geen reden bedenken om het te doen. Ik heb er een paar voorbeelden van in mijn .profile die door veel Bourne-shells is uitgevoerd. [$IFS] won ‘ natuurlijk niet wat bedoeld was als IFS bepaalde niet-standaard waarden (leeg (of niet ingesteld), met ], beginnend met ! of ^) .

Antwoord

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 

Reacties

  • hierdoor wordt elk witruimteteken verwijderd, niet slechts een enkele spatie, toch? bedankt

Answer

Om te testen of de variabele leeg is of spaties bevat, kun je ook deze code gebruiken:

${name:?variable is empty} 

Reacties

  • Ik denk dat je antwoord is afgekeurd omdat de ” of spaties bevatten ” is niet waar.
  • wees voorzichtig – dat doodt de huidige shell. Het is beter om het in een (: $ {subshell?}) Te plaatsen. Ook – dat zal naar stderr schrijven – wilt u waarschijnlijk omleiden. En het belangrijkste dat evalueert naar de werkelijke waarde van de variabele ‘ als deze niet is uitgeschakeld of null is. Als er ‘ een commando in staat, heb je het gewoon uitgevoerd. ‘ is het beste om die test uit te voeren op :.
  • hoe het de shell zal doden. en u kunt dit ook testen, definieer eerst name=aaaa en voer vervolgens dit commando uit echo ${name:?variable is empty} het zal de waarde van de variabelenaam afdrukken en nu dit commando uitvoeren echo ${name1:?variable is empty} het zal -sh: name1: variable is empty
  • Ja – echo ${name:?variable is empty} afdrukken zal ofwel evalueren naar $name ‘ s niet-nulwaarde of het zal de shell doden. Dus om dezelfde reden mag u ‘ niet prompt > $randomvar doen en ${var?} – als daar ‘ een commando daarin bevat, het ‘ wordt waarschijnlijk uitgevoerd – en je hoeft ‘ t weet wat het is. Een interactieve shell ‘ hoeft niet af te sluiten – daarom de jouwe niet ‘ t. Als u echter enkele tests wilt zien, zijn er veel hier. . Deze is niet ‘ t zo lang …

Answer

De code die u heeft gepost [[ ! -z $param ]] && echo "I am not zero" zal I am not zero afdrukken als param is ofwel niet ingesteld / niet gedefinieerd of leeg (in bash, ksh en zsh).

Aan ook print if param bevat alleen spaties (verwijder spaties), POSIXly (voor een breder bereik van shells):

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

Uitleg:

  • Een ${param# … } verwijdert een leidende tekst.
  • Die voorlooptekst wordt gegeven door: ${param%%[! ]*}
  • Die wordt uitgebreid tot alle spaties vóór elk niet-spatie teken, dwz alle voorloopspaties.

Het eindresultaat van de hele uitbreiding is dat alle voorloopspaties worden verwijderd.

Dit uitgebreide resultaat wordt getest als het een lengte heeft van 0.

  • Als het resultaat leeg is, dan was de variabele leeg, of
  • het verwijderen van de voorloopspaties maakte het leeg.

Daarom, als de test waar is, was de variabele al leeg of had er alleen spaties in.


Het concept is eenvoudig uit te breiden naar meer karaktertypen. Om ook tabbladen op te nemen, plaatst u een expliciete tab binnen de expressie tussen haakjes:

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

of gebruik een variabele waarvan de tekens moeten worden verwijderd:

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

of je kunt een POSIX “character class expression” gebruiken (blanco betekent spatie en tab):

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

Answer

Om te controleren of variabele alleen spaties bevat, ook in een meerregelige variabele , probeer dit:

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

Of met xargs:

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

Of met sed:

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

Antwoord

Probeer dit:

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

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *