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$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
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"*
procase
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.