Test of een string een substring bevat

Ik heb de code

file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi 

Ik test if file “gen” bevat. De uitvoer is “False”. Leuk!

Het probleem is wanneer ik “gen” vervang door een variabele testseq:

file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi 

Nu is de uitvoer “Waar”. Hoe kan dat nou? Hoe het probleem oplossen?

Opmerkingen

Answer

Je moet de variabele met een van de volgende manieren:

  • $file == *_"$testseq"_* (hier $testseq beschouwd als een vaste string)

  • $file == *_${testseq}_* (hier $testseq beschouwd als een patroon).

Of de _ onmiddellijk na de naam van de variabele zal worden beschouwd als onderdeel van de variabele “s name (het is een geldig teken in een variabelenaam).

Opmerkingen

  • Correct antwoord zoals het van toepassing is op OP, maar zonder draagbaar te zijn . (Dit is geen kritiek op het gegeven antwoord, alleen een waarschuwing voor lezers). 😉

Antwoord

Gebruik de =~ -operat of om vergelijkingen met reguliere expressies te maken:

#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi 

Op deze manier zal het vergelijken als $file $testseq over de inhoud ervan.

user@host:~$ ./string.sh False 

Als ik testseq="Const" verander:

user@host:~$ ./string.sh True 

Maar wees voorzichtig met wat u $testseq voedt. Als de tekenreeks erop op de een of andere manier een regex vertegenwoordigt (zoals [0-9] bijvoorbeeld), is er een grotere kans om een “match” te activeren.

Referentie :

Reacties

  • Het lijkt erop dat dit antwoord is voor " bash " alleen

Antwoord

file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac 

Het gebruik van case ... esac is een van de eenvoudigste manieren om een patroonovereenkomst op een draagbare manier uit te voeren. Het werkt als een “switch” -instructie in andere talen (bash, zsh en ksh93 stelt je ook in staat om fall-through te doen op verschillende incompatibele manieren). De gebruikte patronen zijn de standaard globbing-patronen voor bestandsnamen.

Het probleem dat u ondervindt, is het feit dat _ een geldig teken is in een variabelenaam. De shell zal dus *_$testseq_* zien als “*_ gevolgd door de waarde van de variabele $testseq_ en een * “. De variabele $testseq_ is ongedefinieerd, dus het wordt uitgebreid naar een lege string, en je krijgt *_*, wat duidelijk overeenkomt met de $file waarde die je hebt. Je mag verwachten True te krijgen zolang de bestandsnaam in $file ten minste één onderstrepingsteken bevat.

begrenst de naam van de variabele, gebruik "..." rond de uitbreiding: *_"$testseq"_*. Dit zou de waarde van de variabele als een string gebruiken. Wil je de waarde van de variabele als een patroon gebruiken, gebruik dan *_${testseq}_*.

Een andere snelle oplossing is om de onderstreept in de waarde van $testseq:

testseq="_gen_" 

en gebruik dan gewoon *"$testseq"* als het patroon (voor een stringvergelijking).

Reacties

  • De shell zal dus zoeken naar een variabele $ testseq_ en niet vinden het en vervang het door een lege string.
  • @Viesturs Dat ' is de kern van het probleem, ja.
  • Voor een substring-zoekopdracht moet *"$testseq"* zijn voor case zoals voor [[...]] (behalve voor zsh tenzij je inschakelen globsubst)
  • Eenvoudiger dan [ "${str##*substr*}" ] || echo True?
  • @Isaac In termen van lezen en begrijpen wat ' s gebeurt, ja. Het ' is ook gemakkelijk om een test uit te breiden met meer testcases zonder een " if-then-elif-then-elif " spaghetti. Hoewel het testen van een enkele string zoals je laat zien (of een string verdwijnt in een vervanging) is korter.

Answer

Gebruik voor de draagbare manier om te testen of een string een substring bevat:

file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present 

Of "${file##*"$testseq"*}" om te voorkomen dat glob-tekens in testseq worden geïnterpreteerd.

Reacties

  • Je ' hebt zoiets nodig als [" $ {file ## * $ testseq *} "! = " $ file " ] omdat in het streepje het grootste voorvoegselpatroon verwijderen is.
  • Nee, @NoelGrandin er is geen wijziging op de meeste shells (inclusief streepje), het grootste voorvoegselpatroon is de hele tekenreeks als de waarde van het variabele subpatroon ($testseq) binnen de waarde $file staat. Probeer: dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="' om te bevestigen dat het streepje de hele tekenreeks zal verwijderen.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *