Hvordan kan jeg teste, om en variabel er tom eller kun indeholder mellemrum?

Følgende bash-syntaks bekræfter, om param ikke er tom:

 [[ ! -z $param ]] 

For eksempel:

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

Ingen output og dens fine.

Men når param er tom bortset fra et (eller flere) mellemrumstegn, så er sagen anderledes:

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

“Jeg er ikke nul “er output.

Hvordan kan jeg ændre testen til at betragte variabler, der kun indeholder mellemrumstegn som tomme?

Kommentarer

  • Fra man test: -z STRING - the length of STRING is zero. Hvis du vil fjerne alle mellemrum i $param, brug ${param// /}
  • WOW der er ikke en simpel trim() -funktion indbygget til nogen * nix overhovedet? Så mange forskellige hacks for at opnå noget så simpelt …
  • @ADTC $ (sed ‘ s / ^ \ s + | \ s + $ // g ‘ < < < $ string) synes mig enkel nok. Hvorfor genopfinde hjulet?
  • Fordi det kunne være skinnere
  • Bare at bemærke, at [[ ! -z $param ]] svarer til test ! -z $param.

Svar

Bemærk først, at -z test er eksplicit til:

strengens længde er nul

Det vil sige, en streng, der kun indeholder mellemrum, skal ikke være sand under -z, fordi den har en længde, der ikke er nul.

Det, du ønsker, er at fjerne mellemrumene fra variablen ved hjælp af udvidelse af mønsterudskiftningsparameter :

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

Dette udvider param variabel og erstatter alle matches i mønsteret (et enkelt mellemrum) med intet, så en streng, der kun har mellemrum, udvides til en tom streng.


nitty-gritty af hvordan det fungerer er, at ${var/pattern/string} erstatter den første længste match af pattern med string. Når pattern starter med / (som ovenfor), erstatter det alle kampene. Da erstatningen er tom, kan vi udelade den endelige / og string -værdien:

$ {parameter / mønster / streng}

mønster udvides til at producere et mønster ligesom i filnavneudvidelse. Parameter udvides, og den længste matchning af mønster i forhold til dens værdi erstattes med streng . Hvis mønster begynder med ‘/’, erstattes alle matches af mønster med streng . Normalt udskiftes kun den første kamp. … Hvis streng er nul, slettes matches af mønster og det / følgende mønster kan udelades.

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

Bemærk dog til stede i ksh (hvor det stammer fra), zsh og bash, at syntaksen ikke er POSIX og bør ikke bruges i sh scripts.

Kommentarer

  • brug sed sagde de … bare echo variablen, de sagde …
  • Hmm. Hvis det er ${var/pattern/string}, skal ‘ t være [[ -z ${param/ /} ]] med mellemrummet mellem skråstregerne at være mønsteret og intet efter at være strengen?
  • @JesseChisholm ” Da erstatningen er tom, kan vi udelade den endelige / og strengværdien “; ” Hvis streng er nul, slettes matches af mønster og det / følgende mønster kan være udeladt. ”
  • @MichaelHomer Svaret [[ -z "${param// }" ]] ser bestemt ud som pattern er tom, og replacement string er et enkelt mellemrum. AH! Jeg ser det nu if pattern begins with a slash Jeg savnede den del. så mønsteret er / , og strengen er afskåret og derfor tom. Tak.
  • bash-note: hvis du kører i sæt -o substantivsæt (sæt -u), og param er ikke sat (snarere end nul eller pladsfyldt), vil dette generere en ubundet variabelfejl. (set + u; …..) ville undtage denne test.

Svar

Den nemme måde at kontrollere, at en streng kun indeholder tegn i et autoriseret sæt, er at teste for tilstedeværelsen af uautoriserede tegn.I stedet for at teste, om strengen kun indeholder mellemrum, skal du teste, om strengen indeholder noget andet tegn end mellemrum. 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 af mellemrum” inkluderer tilfældet med en tom (eller uset) variabel.

Det kan være en god idé at teste for enhver blanktegn. Brug [[ $param = *[^[:space:]]* ]] til at bruge landestandardindstillinger eller hvilken som helst eksplicit liste over tegn i mellemrum, du vil teste for, f.eks. [[ $param = *[$" \t\n"]* ]] for at teste plads, fane eller ny linje.

Matchning af en streng mod et mønster med = inden for [[ … ]] er en ksh-udvidelse (findes også i bash og zsh). I enhver Bourne / POSIX-stil kan du bruge case -konstruktionen til at matche en streng mod et mønster. Bemærk, at standard shell-mønstre bruger ! til at negere et tegnsæt i stedet for ^ som i de fleste syntakser med almindeligt udtryk.

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

For at teste for mellemrumstegn er $"…" syntaksen specifik for ksh / bash / zsh; du kan indsætte disse tegn i dit script bogstaveligt (bemærk, at en ny linje skal være inden for anførselstegn, da tilbageslag + ny linje udvides til ingenting) eller generere dem, fx

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

Kommentarer

  • Dette er næsten fremragende – men det svarer endnu ikke på spørgsmålet som stillet. Det kan i øjeblikket fortælle dig forskellen mellem en uset eller tom skalvariabel og en, der kun indeholder mellemrum. Hvis du accepterer mit forslag, vil du tilføje param-udvidelsesformularen, der endnu ikke er konverteret af noget andet svar, der eksplicit tester en shellvariabel for at blive indstillet – jeg mener ${var?not set} – bestået testen og overlevende ville sikre, at en variabel, der matches med din *) case, f.eks. vil have et endeligt svar.
  • Korrektion – dette ville faktisk besvare det oprindeligt stillede spørgsmål, men det er siden blevet redigeret på en sådan måde, at det fundamentalt ændrer spørgsmålets betydning og derfor annullerer dit svar.
  • Du har brug for [[ $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 at skelne mellem blank , ikke-blank , tom , frakoblet :

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

[:blank:] er til vandrette afstandstegn (mellemrum og fane i A. SCII, men der er sandsynligvis et par flere i dit land; nogle systemer inkluderer det ikke-brudende mellemrum (hvis tilgængeligt), nogle vandt “t). Hvis du også vil have lodrette mellemrumstegn (som newline eller form-feed), skal du erstatte [:blank:] med [:space:].

Kommentarer

  • POSIXly er ideel, fordi det fungerer med (uden tvivl bedre) bindestreg.
  • zsh synes at have problemer med [![:blank:]], det hæver :b er ugyldig modifikator. I sh og ksh emulerer, hæver det begivenhed ikke fundet for [
  • @cuonglm, hvad prøvede du? var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac' er OK for mig. Den begivenhed, der ikke blev fundet, ville kun være til interaktive skaller.
  • @St é phaneChazelas: Ah, højre, jeg prøvede med interaktive skaller. :b ugyldig modifikator er lidt underlig.
  • @FranklinYu, på OS / X sh er bygget med --enable-xpg-echo-default og --enable-strict-posix-default for at være Unix-kompatibel (som involverer echo '\t' udsendelse af en fane).

Svar

Den eneste resterende grund til at skrive et shell-script i stedet for et script i et godt scripting-sprog er, hvis ekstrem bærbarhed er en altoverskyggende bekymring. Arven /bin/sh er det eneste, du kan være sikker på, at du har, men Perl er for eksempel mere sandsynligvis tilgængelig på tværs af platforme end Bash. Derfor skal du aldrig skrive shell-scripts, der bruger funktioner, der ikke er “t ægte universelle – og husk på, at flere proprietære Unix-leverandører frøs deres shell-miljø inden POSIX.1-2001 .

Der er en bærbar måde at lave denne test på, men du skal bruge tr:

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

(Standardværdien af $IFS er bekvemt et mellemrum, en fane og en ny linje.)

(printf builtin er i sig selv let transportabel, men at stole på det er meget mindre besvær end at finde ud af, hvilken variant af echo du har.)

Kommentarer

  • At ‘ er en smule indviklet.Den sædvanlige bærbare måde at teste, om en streng indeholder bestemte tegn, er med case .
  • @Gilles Jeg tror ikke ‘ Jeg tror ikke det ‘ er muligt at skrive en case glob til registrere en streng, der enten er tom eller kun indeholder tegn i mellemrummet. (Det ville være let med en regexp, men case gør ikke ‘ t regexps. Konstruktionen i dit svar vandt ‘ fungerer ikke, hvis du er interesseret i nye linjer.)
  • Jeg gav mellemrum som et eksempel i mit svar, fordi at ‘ er hvad spørgsmålet bad om. Det ‘ er lige så let at teste for mellemrumstegn: case $param in *[![:space:]]*) …. Hvis du vil teste for IFS tegn, kan du bruge mønsteret *[$IFS]*.
  • @mikeserv In a really alvorligt defensivt script, indstiller du eksplicit IFS til <space><tab><newline> i starten og derefter aldrig rører ved det igen. Jeg troede, at ‘ d var en distraktion.
  • Med hensyn til variabler i mønstre, tror jeg, det fungerer i alle Bourne-versioner og alle POSIX-skaller; det ville kræve ekstra kode for at opdage sagsmønstre og deaktivere variabel udvidelse, og jeg kan ‘ ikke tænke på en grund til at gøre det. Jeg har et par forekomster af det i min .profile, som er blevet udført af mange Bourne-skaller. Naturligvis [$IFS] vandt ‘ t gør, hvad der var beregnet, hvis IFS har visse ikke-standarder værdier (tomme (eller ikke indstillet), der indeholder ], begyndende 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 slipper enhver hvid plads karakter, ikke kun et enkelt mellemrum, ikke? tak

Svar

For at teste, om variablen er tom eller indeholder mellemrum, kan du også bruge denne kode:

${name:?variable is empty} 

Kommentarer

  • Jeg tror, dit svar er nedstemt, fordi ” eller indeholde mellemrum ” er ikke sandt.
  • pas på – det dræber den aktuelle skal. Bedre at sætte det i en (: $ {subshell?}). Også – der vil skrive til stderr – vil du sandsynligvis omdirigere. Og vigtigst der evalueres til variablen ‘ s faktiske værdi, hvis den ikke er frakoblet eller nul. Hvis der ‘ er en kommando derinde, kørte du den bare. Det ‘ er bedst at køre testen på :.
  • hvordan det vil dræbe shell. og du kan også teste dette, først definere name=aaaa derefter køre denne kommando echo ${name:?variable is empty} det vil udskrive værdien af variabelnavnet og køre nu denne kommando echo ${name1:?variable is empty} den udskriver -sh: name1: variabel er tom
  • Ja – echo ${name:?variable is empty} vil enten evaluere til $name ‘ s ikke-nulværdi eller det vil dræbe skallen. Så af samme grund gør du ikke ‘ t prompt > $randomvar Du skal heller ikke ${var?} – hvis der ‘ en kommando derinde, den ‘ vil sandsynligvis køre – og du don ‘ t ved hvad det er. En interaktiv shell behøver ikke ‘ at afslutte – det er derfor, din ikke ‘ t. Stadig, hvis du vil se nogle tests, er der mange af dem her. . Denne er ikke ‘ t lige så længe …

Svar

Koden, du sendte [[ ! -z $param ]] && echo "I am not zero", udskriver I am not zero param er enten ikke indstillet / udefineret eller tom (i bash, ksh og zsh).

Til også udskriv hvis param kun indeholder mellemrum (fjern mellemrum), POSIXly (for et bredere udvalg af skaller):

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

Forklaring:

  • A ${param# … } fjerner en ledende tekst.
  • Den førende tekst er givet af: ${param%%[! ]*}
  • Hvilket udvides til alle mellemrum før ethvert ikke-mellemrum tegn, dvs. alle de førende mellemrum.

Slutresultatet af hele udvidelsen er, at alle førende rum fjernes.

Dette udvidede resultat testes med længde 0.

  • Hvis resultatet er tomt, var enten variablen tom eller
  • fjernelse af de førende mellemrum gjorde det tomt.

Hvis testen er sand, var variablen enten tom allerede eller havde kun mellemrum inde i den.


Konceptet er let at udvide til mere karaktertyper. Hvis du også vil inkludere faner, skal du placere en eksplicit fane inde i parentesudtrykket:

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

eller bruge en variabel med de tegn, du har brug for fjernet:

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

eller du kan bruge noget POSIX “tegnklasseudtryk” (blank betyder mellemrum og fane):

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

Svar

For at kontrollere, om variablen kun har mellemrum, inklusive i en variabel med flere linier , 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 

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *