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.
-
zsh
synes at have problemer med[![:blank:]]
, det hæver:b
er ugyldig modifikator. Ish
ogksh
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 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
case
glob til registrere en streng, der enten er tom eller kun indeholder tegn i mellemrummet. (Det ville være let med en regexp, mencase
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 forIFS
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, hvisIFS
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 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 > $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
sed
sagde de … bareecho
variablen, 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 sompattern
er tom, ogreplacement string
er et enkelt mellemrum. AH! Jeg ser det nuif pattern begins with a slash
Jeg savnede den del. så mønsteret er/
, og strengen er afskåret og derfor tom. Tak.