Hvordan kan jeg teste om en variabel er tom eller bare inneholder mellomrom?

Følgende bash-syntaks bekrefter om param ikke er tom:

 [[ ! -z $param ]] 

For eksempel:

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

Ingen utgang og dens fine.

Men når param er tom bortsett fra ett (eller flere) mellomromstegn, så er saken annerledes:

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

«Jeg er ikke null «sendes ut.

Hvordan kan jeg endre testen for å betrakte variabler som bare inneholder mellomromstegn som tomme?

Kommentarer

  • Fra man test: -z STRING - the length of STRING is zero. Hvis du vil fjerne alle mellomrom i $param, bruk ${param// /}
  • WOW det er ikke en enkel trim() -funksjon innebygd for noen * nix i det hele tatt? Så mange forskjellige hack for å oppnå noe så enkelt …
  • @ADTC $ (sed ‘ s / ^ \ s + | \ s + $ // g ‘ < < < $ string) virker enkelt nok for meg. Hvorfor finne opp hjulet på nytt?
  • Fordi det kan være skinnende
  • Bare å merke seg at [[ ! -z $param ]] tilsvarer test ! -z $param.

Svar

Vær først oppmerksom på at -z test er eksplisitt for:

lengden på strengen er null

Det vil si at en streng som bare inneholder mellomrom, skal ikke være sant under -z, fordi den har en lengde som ikke er null.

Det du ønsker er å fjerne mellomromene fra variabelen ved hjelp av Utvidelse av parameterutskiftningsparameter :

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

Dette utvider param variabel og erstatter alle treff i mønsteret (et enkelt mellomrom) med ingenting, så en streng som bare har mellomrom vil utvides til en tom streng.


nitty-gritty av hvordan det fungerer er at ${var/pattern/string} erstatter den første lengste kampen på pattern med string. Når pattern starter med / (som ovenfor), erstatter det alle treffene. Fordi erstatningen er tom, kan vi utelate den endelige / og string -verdien:

$ {parameter / mønster / streng}

mønsteret utvides for å produsere et mønster akkurat som i filnavnutvidelse. Parameter utvides, og det lengste samsvaret mellom mønster og verdien erstattes med streng . Hvis mønster begynner med ‘/’, erstattes alle treff for mønster med streng . Normalt erstattes bare den første kampen. … Hvis streng er null, blir samsvar av mønster slettet, og / følgende mønster kan utelates.

Når alt kommer til alt, ender vi opp med ${param// } for å slette alle mellomrom.

Merk at skjønt til stede i ksh (hvor den stammer fra), zsh og bash, at syntaksen ikke er POSIX og skal ikke brukes i sh skript.

Kommentarer

  • bruk sed sa de … bare echo variabelen de sa …
  • Hmm. Hvis det er ${var/pattern/string}, burde det ikke være ‘ t det skal være [[ -z ${param/ /} ]] med mellomrommet mellom skråstreken å være mønsteret og ingenting etter å være strengen?
  • @JesseChisholm » Fordi erstatningen er tom, kan vi utelate den endelige / og strengverdien «; » Hvis streng er null, blir samsvar av mønster slettet, og / følgende mønster kan være utelatt. »
  • @MichaelHomer Svaret [[ -z "${param// }" ]] ser sikkert ut som pattern er tom og replacement string er et enkelt mellomrom. AH! Jeg ser det nå if pattern begins with a slash Jeg savnet den delen. så mønsteret er / og strengen er avblåst og derfor tom. Takk.
  • bash note: hvis du kjører i sett -o substantivsett (sett -u), og param er usett (i stedet for null eller mellomrom), vil dette generere en ubundet variabelfeil. (set + u; …..) ville unntatt denne testen.

Svar

Den enkle måten å kontrollere at en streng bare inneholder tegn i et autorisert sett, er å teste for tilstedeværelsen av uautoriserte tegn.I stedet for å teste om strengen bare inneholder mellomrom, kan du teste om strengen inneholder noe annet tegn enn mellomrom. I bash, ksh eller zsh:

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

“Består kun av mellomrom” inkluderer tilfellet med en tom (eller usett) variabel.

Det kan være lurt å teste for hvilken som helst blanktegn. Bruk [[ $param = *[^[:space:]]* ]] til å bruke lokale innstillinger, eller hvilken eksplisitt liste med tegn som du vil teste for, f.eks. [[ $param = *[$" \t\n"]* ]] for å teste for mellomrom, fane eller ny linje.

Matching av en streng mot et mønster med = inne i [[ … ]] er en ksh-utvidelse (finnes også i bash og zsh). I en hvilken som helst Bourne / POSIX-stil kan du bruke case -konstruksjonen til å matche en streng mot et mønster. Merk at standard skallmønstre bruker ! for å negere tegnsett, i stedet for ^ som i de fleste syntakser med vanlig uttrykk.

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

For å teste for mellomromstegn, er $"…" syntaksen spesifikk for ksh / bash / zsh; du kan sette inn disse tegnene i skriptet ditt bokstavelig (merk at en ny linje må være innenfor anførselstegn, ettersom tilbakeslag + ny linje utvides til ingenting), eller generere dem, f.eks.

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

Kommentarer

  • Dette er nesten utmerket – men foreløpig svarer det ikke på spørsmålet som stilt. Det kan for øyeblikket fortelle deg forskjellen mellom en uset eller tom skallvariabel og en som bare inneholder mellomrom. Hvis du godtar mitt forslag, vil du legge til param-utvidelsesskjemaet som ennå ikke er konvertert av noe annet svar som eksplisitt tester en skallvariabel for å bli satt – jeg mener ${var?not set} – bestått testen og overlever ville sørge for at en variabel matchet med *) case, for eksempel, ville gi et definitivt svar.
  • Rettelse – dette vil faktisk svare på spørsmålet som ble stilt opprinnelig, men det har siden blitt redigert på en slik måte at det fundamentalt endrer betydningen av spørsmålet og derfor ugyldiggjør svaret ditt.
  • Du trenger [[ $param = *[!\ ]* ]] i mksh.

Svar

POSIXly:

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

For å skille mellom blank , ikke-blank , tom , unset :

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

[:blank:] er for horisontale avstandstegn (mellomrom og fane i A. SCII, men det er sannsynligvis noen flere i ditt område; noen systemer vil inkludere det ikke-knekkende rommet (hvor det er tilgjengelig), noen vil ikke «t». Hvis du også vil ha vertikale mellomromstegn (som ny linje eller form-feed), erstatt [:blank:] med [:space:].

Kommentarer

  • POSIXly er ideelt fordi det vil fungere med (uten tvil bedre) dash.
  • zsh ser ut til å ha problemer med [![:blank:]], det hever :b er ugyldig modifikator. I sh og ksh emulerer det, det øker hendelsen ikke funnet for [
  • @cuonglm, hva prøvde du? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' er OK for meg. Arrangementet som ikke ble funnet ville bare være for interaktive skjell.
  • @St é phaneChazelas: Ah, ikke sant, jeg prøvde med interaktive skall. :b ugyldig modifikator er litt rart.
  • @FranklinYu, på OS / X sh er bygget med --enable-xpg-echo-default og --enable-strict-posix-default for å være Unix-kompatibel (som involverer echo '\t' skriver ut en fane).

Svar

Den eneste gjenværende grunnen til å skrive et skallskript, i stedet for et skript i et godt skriptspråk, er hvis ekstrem bærbarhet er en overordnet bekymring. Arven /bin/sh er det eneste du kan være sikker på at du har, men Perl er for eksempel mer sannsynlig å være tilgjengelig på tvers av plattformer enn Bash. Derfor skal du aldri skrive skallskripter som bruker funksjoner som ikke er «virkelig universelle – og husk at flere proprietære Unix-leverandører frøs skallmiljøet sitt før POSIX.1-2001 .

Det er en bærbar måte å gjøre denne testen på, men du må bruke tr:

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

(Standardverdien for $IFS er praktisk nok et mellomrom, en fane og en ny linje.)

(printf innebygd er i seg selv lett bærbar, men å stole på det er mye mindre problemer enn å finne ut hvilken variant av echo du har.)

Kommentarer

  • At ‘ er litt innviklet.Den vanlige bærbare måten å teste om en streng inneholder visse tegn er med case .
  • @Gilles Jeg tror ikke ‘ jeg tror det ‘ er mulig å skrive en case glob til oppdage en streng som enten er tom, eller som bare inneholder mellomromstegn. (Det ville være enkelt med en regexp, men case ‘ t gjør regexps. Konstruksjonen i svaret ditt vant ‘ t fungerer hvis du bryr deg om nye linjer.)
  • Jeg ga mellomrom som et eksempel i svaret mitt fordi det ‘ er hva spørsmålet spurte om. Det er ‘ like enkelt å teste for mellomromstegn: case $param in *[![:space:]]*) …. Hvis du vil teste for IFS tegn, kan du bruke mønsteret *[$IFS]*.
  • @mikeserv In a really alvorlig defensivt skript, setter du eksplisitt IFS til <space><tab><newline> i begynnelsen og berører den aldri mer. Jeg trodde at ‘ d var en distraksjon.
  • Når det gjelder variabler i mønstre, tror jeg det fungerer i alle Bourne-versjoner og alle POSIX-skall; det vil kreve ekstra kode for å oppdage saksmønstre og slå av variabel utvidelse, og jeg kan ‘ ikke tenke på en grunn til å gjøre det. Jeg har et par forekomster av det i .profile som er blitt henrettet av mange Bourne-skall. Selvfølgelig [$IFS] vant ‘ t gjør det som var ment hvis IFS har visse ikke-standarder verdier (tomme (eller ikke angitt), som inneholder ], og starter med ! eller ^) .

Svar

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 

Kommentarer

  • dette blir kvitt hvite mellomromskarakterer, ikke bare ett mellomrom, ikke sant? takk

Svar

For å teste om variabelen er tom eller inneholder mellomrom, kan du også bruke denne koden:

${name:?variable is empty} 

Kommentarer

  • Jeg tror svaret ditt blir nedstemt fordi » eller inneholde mellomrom » er ikke sant.
  • vær forsiktig – det dreper det nåværende skallet. Bedre å sette det i en (: $ {subshell?}). Også – som vil skrive til stderr – vil du sannsynligvis omdirigere. Og det viktigste som evalueres til variabelen ‘ s faktiske verdi hvis den ikke er satt eller null. Hvis det ‘ er en kommando der inne, kjørte du den bare. Det er ‘ best å kjøre testen på :.
  • hvordan den vil drepe skallet. og du kan også teste dette, først definere name=aaaa kjør deretter denne kommandoen echo ${name:?variable is empty} den vil skrive ut verdien av variabelnavnet og nå kjøre denne kommandoen echo ${name1:?variable is empty} den vil skrive ut -sh: name1: variabel er tom
  • Ja – echo ${name:?variable is empty} vil enten evaluere til $name ‘ s ikke-nullverdi eller det vil drepe skallet. Så av samme grunn gjør du ikke ‘ t prompt > $randomvar Du skal heller ikke ${var?} – hvis der ‘ en kommando der inne, den ‘ vil sannsynligvis løpe – og du don ‘ t vet hva det er. Et interaktivt skall trenger ikke ‘ ikke å avslutte – det er grunnen til at ditt ikke ‘ t. Likevel, hvis du vil se noen tester, er det mange av dem her. . Denne er ikke ‘ t ganske lenge …

Svar

Koden du la ut [[ ! -z $param ]] && echo "I am not zero" vil skrive ut I am not zero hvis param er enten usett / udefinert eller tom (i bash, ksh og zsh).

Til også skriv ut hvis paramet bare inneholder mellomrom (fjern mellomrom), POSIXly (for et bredere utvalg av skjell):

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

Forklaring:

  • A ${param# … } fjerner en ledende tekst.
  • Den ledende teksten er gitt av: ${param%%[! ]*}
  • Som utvides til alle mellomrom før ethvert ikke-mellomrom tegn, dvs. alle ledende mellomrom.

Sluttresultatet av hele utvidelsen er at alle ledende mellomrom blir fjernet.

Dette utvidede resultatet testes hvis det er av lengde 0.

  • Hvis resultatet er tomt, var enten variabelen tom, eller
  • fjerning av de ledende mellomrommene gjorde det tomt.

Hvis testen er sant, var variabelen enten tom allerede eller hadde bare mellomrom.


Konseptet er enkelt å utvide til mer karaktertyper. For å også inkludere faner, plasser en eksplisitt fane i parentesuttrykket:

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

eller bruk en variabel med tegnene du trenger fjernet:

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

eller du kan bruke noe POSIX «tegnklasseuttrykk» (blank betyr mellomrom og fane):

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

Svar

For å sjekke om variabelen bare har mellomrom, inkludert i en variabel med flere linjer , prøv dette:

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

Eller med xargs:

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

Eller med sed:

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

Svar

Prøv dette:

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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *