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 ]]
tilsvarertest ! -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
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 = *[!\ ]* ]]
imksh
.
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. Ish
ogksh
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 involvererecho '\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, mencase
‘ 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 forIFS
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 hvisIFS
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 kommandoenecho ${name:?variable is empty}
den vil skrive ut verdien av variabelnavnet og nå kjøre denne kommandoenecho ${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 ‘ tprompt > $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
sed
sa de … bareecho
variabelen de sa …${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?[[ -z "${param// }" ]]
ser sikkert ut sompattern
er tom ogreplacement 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.