Testa om en sträng innehåller en sträng

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

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ör case 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.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *