Jag har koden
file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi
I test om file innehåller ”gen”. Resultatet är ”Falskt”. Trevligt!
Problemet är när jag ersätter ”gen” med en variabel testseq:
file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi
Nu är utdata ”True”. Hur kommer det sig? Hur åtgärdar du problemet?
Kommentarer
- Möjlig duplikat av Shell-test för att hitta ett mönster i en sträng
Svar
Du måste interpolera $testseq variabel på något av följande sätt:
-
$file == *_"$testseq"_*(här$testseqbetraktas som en fast sträng) -
$file == *_${testseq}_*(här$testseqbetraktas som ett mönster).
Eller _ omedelbart efter variabelns namn tas som en del av variabeln ”s namn (det är ett giltigt tecken i ett variabelnamn).
Kommentarer
- Rätt svar eftersom det gäller OP, men utan att vara bärbart . (Detta är ingen kritik mot det tillhandahållna svaret, bara en varning till läsarna). 😉
Svar
Använd operatorn =~ eller för att jämföra reguljära uttryck:
#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi
På det här sättet jämförs det om $file har $testseq om dess innehåll.
user@host:~$ ./string.sh False
Om jag ändrar testseq="Const":
user@host:~$ ./string.sh True
Men var försiktig med vad du matar $testseq med. Om strängen på den på något sätt representerar en regex (till exempel [0-9]) finns det större chans att utlösa en ”matchning”.
Referens :
Kommentarer
- Det verkar som att detta svar är för " bash "
Svar
file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac
Att använda case ... esac är ett av de enklaste sätten att utföra en mönstermatchning på ett bärbart sätt. Det fungerar som ett ”switch” -uttalande på andra språk (bash, zsh och ksh93 låter dig också göra genomslag på olika inkompatibla sätt). Mönstren som används är standardmönster för globbearbetning.
Problemet du har beror på att _ är ett giltigt tecken i ett variabelt namn. Skalet ser alltså *_$testseq_* som ”*_ följt av värdet på variabeln $testseq_ och en * ”. Variabeln $testseq_ är odefinierad, så den utvidgas till en tom sträng och du får *_*, som uppenbarligen matchar $file värde som du har. Du kan förvänta dig att få True så länge filnamnet i $file innehåller minst en understrykning.
För att ordentligt avgränsa variabelns namn, använd "..." runt expansionen: *_"$testseq"_*. Detta skulle använda variabelns värde som en sträng. Vill du använda värdet på variabeln som ett mönster , använd *_${testseq}_* istället.
En annan snabb lösning är att inkludera understryker värdet av $testseq:
testseq="_gen_"
och använd bara *"$testseq"* som mönster (för strängjämförelse).
Kommentarer
- Så skalet kommer att leta efter en variabel $ testseq_ och inte hitta och ersätt den med en tom sträng.
- @Viesturs Att ' s är kärnan i frågan, ja.
- För en strängsökning bör vara
*"$testseq"*förcasesom för[[...]](utom zsh om du inte aktivera globsubst) - Enklare än
[ "${str##*substr*}" ] || echo True? - @Isaac När det gäller läsning och förståelse vad ' s händer, ja. ' är också lätt att förlänga ett test med fler testfall utan att få en " if-then-elif-then-elif " spaghetti. Även om du testar en enda sträng så som du visar (om en sträng försvinner i en ersättning) är kortare.
Svar
För det bärbara sättet att testa om en sträng innehåller en substring, använd:
file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present
Eller "${file##*"$testseq"*}" för att undvika tolkning av globtecken i testseq.
Kommentarer
- Du ' d behöver något som [" $ {file ## * $ testseq *} "! = " $ file " ] för i streck som är Ta bort största prefixmönster.
- Nej, @NoelGrandin det finns ingen förändring på de flesta skalen (inklusive streck), Största prefixmönstret är hela strängen om det variabla undermönstret (
$testseq) finns i värdet$file. Försök:dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="'för att bekräfta att streck tar bort hela strängen.