Mám kód
file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi
Testuji pokud file obsahuje „gen“. Výstup je „False“. Pěkné!
Problém je v tom, že když nahradím „gen“ proměnnou testseq:
file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi
Nyní je výstup „True“. Jak by to jen mohlo být? Jak problém vyřešit?
Komentáře
- Možný duplikát Shell testu k nalezení vzoru v řetězci
Odpověď
Je třeba interpolovat $testseq proměnná jedním z následujících způsobů:
-
$file == *_"$testseq"_*(zde$testseqpovažován za pevný řetězec) -
$file == *_${testseq}_*(zde$testseqpovažován za vzor).
Nebo _ bezprostředně za názvem proměnné bude považován za součást proměnné name (it „sa valid character in a variable name).
Komentáře
- Správná odpověď, jak se týká OP, ale bez možnosti přenosu . (Toto není kritika poskytnuté odpovědi, pouze varování pro čtenáře.) 😉
Odpověď
Použijte =~ operat nebo provést srovnání regulárních výrazů:
#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi
Tímto způsobem se porovná, pokud $file má $testseq o obsahu.
user@host:~$ ./string.sh False
Pokud změním testseq="Const":
user@host:~$ ./string.sh True
Buďte však opatrní, čím krmíte $testseq. Pokud řetězec na něm nějakým způsobem představuje regex (například [0-9]), existuje větší šance na spuštění „shody“.
Reference :
Komentáře
- Vypadá to, že tato odpověď je pro " bash " pouze
odpověď
file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac
Použití case ... esac je jedním z nejjednodušších způsobů, jak provést shodu vzorů přenosným způsobem. Funguje jako příkaz „switch“ v jiných jazycích (bash, zsh a ksh93 také umožňuje provádět propad různými nekompatibilními způsoby). Používané vzory jsou standardní vzory globování názvů souborů.
Problém, který máte, je způsoben skutečností, že _ je platný znak v názvu proměnné. Prostředí tak uvidí *_$testseq_* jako „*_ následované hodnotou proměnné $testseq_ a * „. Proměnná $testseq_ není definována, takže bude rozšířena na prázdný řetězec a vy skončíte s *_*, který zjevně odpovídá $file hodnotu, kterou máte. Můžete očekávat, že True získáte, pokud název souboru v $file obsahuje alespoň jedno podtržítko.
Správně oddělte název proměnné, použijte "..." kolem rozšíření: *_"$testseq"_*. Tím by se hodnota proměnné použila jako řetězec. Chcete použít hodnotu proměnné jako vzor , použijte místo toho *_${testseq}_*.
Další rychlou opravou je zahrnout podtržítka v hodnotě $testseq:
testseq="_gen_"
a poté stačí použít *"$testseq"* jako vzor (pro porovnání řetězců).
Komentáře
- Takže prostředí bude hledat proměnnou $ testseq_ a nenajde a nahraďte jej prázdným řetězcem.
- @Viesturs To ' s je jádrem problému, ano.
- vyhledávání podřetězců by mělo být
*"$testseq"*procasejako pro[[...]](kromě zsh, pokud povolit globsubst) - Jednodušší než
[ "${str##*substr*}" ] || echo True? - @Isaac Z hlediska čtení a porozumění tomu, co ' se děje, ano. ' Je také snadné rozšířit jeden test o více testovacích případů bez získání " if-then-elif-then-elif " špagety. Ačkoli testování jednoho řetězce způsobem, který ukážete (zda řetězec v substituci zmizí), je kratší.
Odpověď
Přenosný způsob, jak otestovat, zda řetězec obsahuje podřetězec, použijte:
file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present
Nebo "${file##*"$testseq"*}" vyhnout se interpretaci globálních znaků v testseq.
Komentáře
- Potřebujete ' něco jako [" $ {file ## * $ testseq *} "! = " $ file " ] protože v pomlčce, která je Odebrat největší vzor předpony.
- Ne, @NoelGrandin u většiny skořápek (včetně pomlčky) nedojde ke změně, největší vzor předpony bude celý řetězec pokud je hodnota proměnné subpattern (
$testseq) obsažena uvnitř hodnoty$file. Zkuste:dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="'potvrdit, že pomlčka odstraní celý řetězec.