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$testseq
betraktas som en fast sträng) -
$file == *_${testseq}_*
(här$testseq
betraktas 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örcase
som 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.