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 tiltest ! -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
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 = *[!\ ]* ]]imksh.
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.
-
zshsynes at have problemer med[![:blank:]], det hæver:ber ugyldig modifikator. Ishogkshemulerer, 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.
:bugyldig modifikator er lidt underlig. - @FranklinYu, på OS / X
sher bygget med--enable-xpg-echo-defaultog--enable-strict-posix-defaultfor at være Unix-kompatibel (som involvererecho '\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
caseglob til registrere en streng, der enten er tom eller kun indeholder tegn i mellemrummet. (Det ville være let med en regexp, mencasegø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 forIFStegn, 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, hvisIFShar 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=aaaaderefter køre denne kommandoecho ${name:?variable is empty}det vil udskrive værdien af variabelnavnet og køre nu denne kommandoecho ${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 ‘ tprompt > $randomvarDu 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
sedsagde de … bareechovariablen, de sagde …${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?[[ -z "${param// }" ]]ser bestemt ud sompatterner tom, ogreplacement stringer et enkelt mellemrum. AH! Jeg ser det nuif pattern begins with a slashJeg savnede den del. så mønsteret er/, og strengen er afskåret og derfor tom. Tak.