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
- Mogelijk duplicaat van Shell-test om een patroon te vinden in een string
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 voorcase
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.