Sprawdź, czy ciąg zawiera podciąg


40

Mam kod

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

Sprawdzam, czy filezawiera „gen”. Wynikiem jest „False”. Miły!

Problem polega na tym, że podstawiam „gen” zmienną testseq:

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

Teraz wyjście ma wartość „True”. Jak to mogło się stać? Jak rozwiązać problem?


Odpowiedzi:


25

Musisz interpolować $testseqzmienną na jeden z następujących sposobów:

  • $file == *_"$testseq"_*(tutaj $testsequważany za stały ciąg)

  • $file == *_${testseq}_*(tutaj $testsequważany za wzór).

Lub _bezpośrednio po nazwie zmiennej zostanie wzięty jako część nazwy zmiennej (jest to prawidłowy znak w nazwie zmiennej).


Prawidłowa odpowiedź dotyczy OP, ale bez przenośności. (To nie jest krytyka podanej odpowiedzi, tylko ostrzeżenie dla czytelników). ;-)
Cbhihe,

28

Użyj =~operatora, aby wykonać porównania wyrażeń regularnych:

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

W ten sposób porówna, jeśli $filema $testseqna swojej zawartości.

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

Jeśli zmienię testseq="Const":

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

Ale uważaj na to, co karmisz $testseq. Jeśli ciąg znaków na nim reprezentuje wyrażenie regularne (jak [0-9]na przykład), istnieje większa szansa na wywołanie „dopasowania”.

Odniesienie :


20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

Używanie case ... esacjest jednym z najprostszych sposobów wykonania dopasowania wzorca w przenośny sposób. Działa jako instrukcja „switch” w innych językach ( bash, zsha ksh93także pozwala na awarię na różne niekompatybilne sposoby). Zastosowane wzorce to standardowe wzorce globowania nazw plików.

Problem, który masz, wynika z faktu, że _jest to prawidłowy znak w nazwie zmiennej. Powłoka będzie zatem widzieć *_$testseq_*jako „ *_po wartości zmiennej $testseq_i *”. Zmienna $testseq_jest niezdefiniowana, więc zostanie rozwinięta do pustego łańcucha, a na końcu skończy się *_*, co oczywiście pasuje do $filewartości, którą masz. Możesz się spodziewać, Trueże nazwa pliku $filezawiera co najmniej jeden znak podkreślenia.

Aby właściwie ograniczają nazwę zmiennej, użytkowania "..."wokół rozbudowy: *_"$testseq"_*. Użyłoby to wartości zmiennej jako łańcucha. Jeśli chcesz użyć wartości zmiennej jako wzorca , użyj *_${testseq}_*zamiast tego.

Innym szybkim rozwiązaniem jest uwzględnienie podkreślników w wartości $testseq:

testseq="_gen_"

a następnie po prostu użyj *"$testseq"*jako wzorca (do porównania łańcucha).


Zatem powłoka będzie szukała zmiennej $ testseq_ i nie znajdzie jej i zastąpi ją pustym łańcuchem.
Viesturs

@Viesturs To jest sedno problemu, tak.
Kusalananda

1
Dla podciągu wyszukiwania powinno być *"$testseq"*dla casejak dla [[...]](z wyjątkiem zsh chyba że włączysz globsubst)
Stéphane Chazelas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.