Sprawdź, czy ciąg zawiera podłańcuch

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

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"* dla case 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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *