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$testseq
betraktet som en fast streng) -
$file == *_${testseq}_*
(her$testseq
betraktet 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"*
forcase
som 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.