Mam kod
file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi
Testuję jeśli file
zawiera „gen”. Wynik to „Fałsz”. Świetnie!
Problem polega na tym, że zastępuję „gen” zmienną testseq
:
file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi
Teraz wynik to „Prawda”. Jak to mogło się stać? Jak naprawić problem?
Komentarze
- Możliwy duplikat Test powłoki w celu znalezienia wzorca w ciągu
Odpowiedź
Musisz interpolować $testseq
zmienną na jeden z następujących sposobów:
-
$file == *_"$testseq"_*
(tutaj$testseq
uważany za ustalony ciąg) -
$file == *_${testseq}_*
(tutaj$testseq
uważany za wzorzec).
Lub _
bezpośrednio po nazwie zmiennej będzie traktowane jako część zmiennej „s name (jest to „prawidłowy znak w nazwie zmiennej).
Komentarze
- Prawidłowa odpowiedź, ponieważ dotyczy OP, ale bez przenośności . (To nie jest krytyka udzielonej odpowiedzi, tylko ostrzeżenie dla czytelników). 😉
Odpowiedź
Użyj operacji =~
lub w celu 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ównuje, czy $file
ma $testseq
w jego zawartości.
user@host:~$ ./string.sh False
Jeśli zmienię testseq="Const"
:
user@host:~$ ./string.sh True
Uważaj jednak na to, czym karmisz $testseq
. Jeśli znajdujący się na nim ciąg w jakiś sposób reprezentuje wyrażenie regularne (na przykład [0-9]
), istnieje większa szansa na wywołanie „dopasowania”.
Materiały referencyjne :
Komentarze
- Wygląda na to, że ta odpowiedź dotyczy " bash "
Odpowiedź
file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac
Użycie case ... esac
to jeden z najprostszych sposobów na wykonanie dopasowania wzorca w sposób przenośny. Działa jako instrukcja „switch” w innych językach (bash
, zsh
i ksh93
pozwala również na wpadanie na różne niezgodne sposoby). Użyte wzorce to standardowe wzorce nazw plików.
Problem, który masz, wynika z faktu, że _
jest prawidłowym znakiem w nazwie zmiennej. Powłoka zobaczy zatem *_$testseq_*
jako „*_
, po którym nastąpi wartość zmiennej $testseq_
i *
„. Zmienna $testseq_
jest niezdefiniowana, więc zostanie rozwinięta do pustego ciągu, a otrzymasz *_*
, który oczywiście pasuje do $file
wartość, którą masz. Możesz spodziewać się True
, o ile nazwa pliku w $file
zawiera co najmniej jedno podkreślenie.
Aby poprawnie ogranicz nazwę zmiennej, użyj "..."
wokół rozwinięcia: *_"$testseq"_*
. Spowoduje to użycie wartości zmiennej jako łańcucha. Czy chciałbyś użyć wartości zmiennej jako wzorca , użyj zamiast tego *_${testseq}_*
.
Kolejnym szybkim rozwiązaniem jest dołączenie podkreśla wartość $testseq
:
testseq="_gen_"
, a następnie po prostu użyj *"$testseq"*
jako wzorzec (dla porównania ciągów).
Komentarze
- Powłoka będzie więc szukała zmiennej $ testseq_ i nie znajdzie i zastąp go pustym ciągiem.
- @Viesturs That ' s jest sercem problemu, tak.
- W przypadku wyszukiwanie podciągów powinno być
*"$testseq"*
dlacase
jak dla[[...]]
(z wyjątkiem zsh, chyba że włącz globsubst) - Prostsze niż
[ "${str##*substr*}" ] || echo True
? - @Isaac Jeśli chodzi o czytanie i rozumienie, co ' dzieje się, tak. ' można również łatwo rozszerzyć jeden test o więcej przypadków testowych bez uzyskiwania " if-then-elif-then-elif " spaghetti. Chociaż testowanie pojedynczego łańcucha w sposób, który pokazujesz (czy ciąg znika w podstawieniu), jest krótszy.
Odpowiedź
W przenośnym sposobie sprawdzenia, czy ciąg zawiera podłańcuch, użyj:
file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present
Lub "${file##*"$testseq"*}"
, aby uniknąć interpretowania znaków glob w testseq
.
Komentarze
- Potrzebujesz ' czegoś takiego jak [" $ {file ## * $ testseq *} "! = " $ file " ] ponieważ w myślniku, który oznacza Usuń największy wzorzec prefiksu.
- Nie, @NoelGrandin nie ma żadnych zmian na większości powłok (w tym myślnik), Największy wzorzec prefiksu będzie całym ciągiem jeśli zmienna subpattern (
$testseq
) jest zawarta w wartości$file
. Spróbuj:dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="'
, aby upewnić się, że myślnik usunie cały ciąg.