Jeg har koden
file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi
I test hvis file inneholder «gen». Resultatet er «False». Fint!
Problemet er når jeg erstatter «gen» med en variabel testseq:
file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi
Nå er utgangen «True». Hvordan kan det være? Hvordan fikser jeg problemet?
Kommentarer
- Mulig duplikat av Shell-test for å finne et mønster i en streng
Svar
Du må interpolere $testseq variabel på en av følgende måter:
-
$file == *_"$testseq"_*(her$testseqbetraktet som en fast streng) -
$file == *_${testseq}_*(her$testseqbetraktet som et mønster).
Eller _ umiddelbart etter variabelens navn blir tatt som en del av variabelen «s navn (det er et gyldig tegn i et variabelnavn).
Kommentarer
- Riktig svar som det gjelder OP, men uten å være bærbart . (Dette er ingen kritikk av det gitte svaret, bare en advarsel til leserne). 😉
Svar
Bruk operasjonen =~ eller for å sammenligne regelmessige uttrykk:
#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi
På denne måten vil det sammenlignes hvis $file har $testseq på innholdet.
user@host:~$ ./string.sh False
Hvis jeg endrer testseq="Const":
user@host:~$ ./string.sh True
Men vær forsiktig med hva du mater $testseq med. Hvis strengen på den på en eller annen måte representerer en regex (for eksempel [0-9]), er det større sjanse for å utløse en «match».
Referanse :
Kommentarer
- Det ser ut til at dette svaret er for " bash " bare
Svar
file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac
Å bruke case ... esac er en av de enkleste måtene å utføre en mønstermatch på en bærbar måte. Det fungerer som en «switch» -erklæring på andre språk (bash, zsh og ksh93 lar deg også gjøre gjennomslag på forskjellige inkompatible måter). Mønstrene som brukes er standard filnavnet globmønstre.
Problemet du har skyldes at _ er et gyldig tegn i et variabelt navn. Skallet vil dermed se *_$testseq_* som «*_ etterfulgt av verdien av variabelen $testseq_ og en * «. Variabelen $testseq_ er udefinert, så den utvides til en tom streng, og du ender opp med *_*, som åpenbart samsvarer med $file verdi du har. Du kan forvente å få True så lenge filnavnet i $file inneholder minst ett understrek.
For å ordentlig avgrense navnet på variabelen, bruk "..." rundt utvidelsen: *_"$testseq"_*. Dette vil bruke verdien av variabelen som en streng. Vil du bruke verdien av variabelen som et mønster , bruk *_${testseq}_* i stedet.
En annen rask løsning er å inkludere understreker verdien av $testseq:
testseq="_gen_"
og så er det bare å bruke *"$testseq"* som mønster (for en strengesammenligning).
Kommentarer
- Så skallet vil se etter en variabel $ testseq_ og ikke finne erstatt den med en tom streng.
- @Viesturs At ' s er kjernen i problemet, ja.
- For en understrengsøk bør det være
*"$testseq"*forcasesom for[[...]](bortsett fra zsh med mindre du aktiver globsubst) - Enklere enn
[ "${str##*substr*}" ] || echo True? - @Isaac Når det gjelder lesing og forståelse av hva ' s skjer, ja. Det ' er også enkelt å utvide en test med flere testsaker uten å få en " if-then-elif-then-elif " spaghetti. Selv om du tester en enkelt streng slik du viser (om en streng forsvinner i en erstatning), er kortere.
Svar
For den bærbare måten å teste om en streng inneholder en understreng, bruk:
file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present
Eller "${file##*"$testseq"*}" for å unngå å tolke globaltegn i testseq.
Kommentarer
- Du ' du trenger noe sånt som [" $ {file ## * $ testseq *} "! = " $ file " ] fordi i dash som er Fjern største prefiksmønster.
- Nei, @NoelGrandin er det ingen endring på de fleste skjell (inkludert bindestrek), vil Største prefiksmønster være hele strengen hvis den variable undermønsteret (
$testseq) er inneholdt i$file-verdien. Prøv:dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="'for å bekrefte at bindestrek vil fjerne hele strengen.