Test om en streng inneholder en understreng

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

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"* for case 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.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *