Vyzkoušejte, zda řetězec obsahuje podřetězec

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

Odpověď

Je třeba interpolovat $testseq proměnná jedním z následujících způsobů:

  • $file == *_"$testseq"_* (zde $testseq považován za pevný řetězec)

  • $file == *_${testseq}_* (zde $testseq považ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$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"* pro case jako 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.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *