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 aantest ! -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
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 inmksh
.
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. Insh
enksh
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 (waarbijecho '\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, maarcase
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 opIFS
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 alsIFS
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 uitecho ${name:?variable is empty}
het zal de waarde van de variabelenaam afdrukken en nu dit commando uitvoerenecho ${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 ‘ nietprompt > $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
sed
ze zeiden … gewoonecho
de variabele die ze zeiden …${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?[[ -z "${param// }" ]]
lijkt zeker op depattern
is leeg en dereplacement string
is een enkele spatie. AH! Ik zie het nuif pattern begins with a slash
Ik heb dat deel gemist. dus het patroon is/
en de string is weggelaten en daarom leeg. Bedankt.