Jeg har koden
file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi
I test hvis file
indeholder “gen”. Outputtet er “Falsk”. Dejligt!
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
Nu er output “sandt”. Hvordan kunne det være? Sådan løses problemet?
Kommentarer
- Mulig duplikat af Shell-test for at finde et mønster i en streng
Svar
Du skal interpolere $testseq
variabel med en af følgende måder:
-
$file == *_"$testseq"_*
(her$testseq
betragtes som en fast streng) -
$file == *_${testseq}_*
(her$testseq
betragtes som et mønster).
Eller _
umiddelbart efter variabelens navn tages som en del af variablen “s navn (det er et gyldigt tegn i et variabelnavn).
Kommentarer
- Korrekt svar, da det gælder for OP, men uden at være bærbart . (Dette er ingen kritik af det leverede svar, bare en advarsel til læserne). 😉
Svar
Brug =~
operat eller for at lave sammenligninger med regelmæssigt udtryk:
#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi
På denne måde sammenlignes det, hvis $file
har $testseq
om dets indhold.
user@host:~$ ./string.sh False
Hvis jeg ændrer testseq="Const"
:
user@host:~$ ./string.sh True
Men pas på, hvad du fodrer $testseq
med. Hvis strengen på den på en eller anden måde repræsenterer en regex (som f.eks. [0-9]
), er der en større chance for at udløse et “match”.
Reference :
Kommentarer
- Det ser ud til, at dette svar er til " bash "
Svar
file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac
Brug af case ... esac
er en af de enkleste måder at udføre et mønstermatch på en bærbar måde. Det fungerer som en “switch” -erklæring på andre sprog (bash
, zsh
og ksh93
giver dig også mulighed for at udføre gennemslag på forskellige uforenelige måder). De anvendte mønstre er standardfilnavnet globmønstre.
Det problem, du har, skyldes, at _
er et gyldigt tegn i et variabelt navn. Skallen vil således se *_$testseq_*
som “*_
efterfulgt af værdien af variablen $testseq_
og en *
“. Variablen $testseq_
er udefineret, så den udvides til en tom streng, og du ender med *_*
, som naturligvis matcher $file
værdi, du har. Du kan forvente at få True
så længe filnavnet i $file
indeholder mindst en understregning.
For korrekt afgrænse navnet på variablen, brug "..."
omkring udvidelsen: *_"$testseq"_*
. Dette vil bruge værdien af variablen som en streng. Vil du bruge værdien af variablen som et mønster , skal du bruge *_${testseq}_*
i stedet.
En anden hurtig løsning er at inkludere understreger værdien af $testseq
:
testseq="_gen_"
og brug derefter bare *"$testseq"*
som mønster (til en strengesammenligning).
Kommentarer
- Så shell vil være på udkig efter en variabel $ testseq_ og ikke finde udskift det med en tom streng.
- @Viesturs At ' s er kernen i problemet, ja.
- For en substringsøgning skal være
*"$testseq"*
forcase
som for[[...]]
(undtagen zsh, medmindre du aktiver globsubst) - Enklere end
[ "${str##*substr*}" ] || echo True
? - @Isaac Med hensyn til læsning og forståelse af hvad ' s sker, ja. ' er også let at udvide en test med flere testsager uden at få en " if-then-elif-then-elif " spaghetti. Selvom du tester en enkelt streng, som du viser (om en streng forsvinder i en erstatning), er kortere.
Svar
For den bærbare måde at teste, om en streng indeholder en understreng, skal du bruge:
file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present
Eller "${file##*"$testseq"*}"
for at undgå at fortolke globaltegn i testseq
.
Kommentarer
- Du ' har brug for noget som [" $ {file ## * $ testseq *} "! = " $ file " ] fordi i bindestreg, der er Fjern største præfiks mønster.
- Nej, @NoelGrandin er der ingen ændring på de fleste skaller (inklusive bindestreg), Største præfiks mønster vil være hele strengen hvis den variable submønster (
$testseq
) værdi er indeholdt i værdien$file
. Prøv:dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="'
for at bekræfte, at bindestreg fjerner hele strengen.