Проверить, содержит ли строка подстроку

42

У меня есть код

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

Я проверяю, fileсодержит ли "gen". Выход «Ложь». Ницца!

Проблема в том, когда я заменяю «gen» переменной testseq :

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

Теперь вывод «True». Как это могло произойти? Как решить проблему?

Виестура
источник

Ответы:

26

Вам необходимо интерполировать $testseqпеременную одним из следующих способов:

  • $file == *_"$testseq"_* (Вот $testseq рассматривается как фиксированная строка)

  • $file == *_${testseq}_*(здесь $testseqрассматривается как образец).

Или _сразу после имени переменной будет взято как часть имени переменной (это допустимый символ в имени переменной).

RomanPerekhrest
источник
Правильный ответ, так как он применяется к OP, но без переносимости. (Это не критика предоставленного ответа, а предупреждение читателей). ;-)
Cbhihe
29

Используйте =~оператор для сравнения регулярных выражений:

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

Таким образом, он будет сравнивать, если $fileимеет $testseqпо своему содержанию.

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

Если я изменюсь testseq="Const":

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

Но будьте осторожны с тем, что вы кормите $testseq. Если строка на нем каким-либо образом представляет регулярное выражение (как, [0-9]например), есть больше шансов вызвать "совпадение".

Ссылка :


источник
20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

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

Использование case ... esac- это один из самых простых способов выполнить сопоставление с образцом переносимым способом. Он работает как оператор «switch» на других языках ( bash, zshи ksh93также позволяет выполнять сквозные операции различными несовместимыми способами). Используемые шаблоны являются стандартными шаблонами подстановки имен файлов.

Проблема, с которой вы столкнулись, связана с тем, что _это допустимый символ в имени переменной. Оболочка, таким образом, будет выглядеть *_$testseq_*как « *_сопровождаемая значением переменной $testseq_и an *». Переменная $testseq_не определена, поэтому она будет расширена до пустой строки, и вы в итоге получите *_*, что, очевидно, соответствует $fileзначению, которое у вас есть. Вы можете рассчитывать получить Trueдо тех пор, пока имя файла $fileсодержит хотя бы одно подчеркивание.

Для того, чтобы правильно разграничить имя переменной, использование "..."вокруг расширения: *_"$testseq"_*. Это будет использовать значение переменной в виде строки. Если вы хотите использовать значение переменной в качестве шаблона , используйте *_${testseq}_*вместо этого.

Еще одно быстрое решение - включить подчеркивание в значение $testseq:

testseq="_gen_"

а затем просто использовать *"$testseq"*в качестве шаблона (для сравнения строк).

Кусалананда
источник
Поэтому оболочка будет искать переменную $ testseq_, не найдет ее и заменит ее пустой строкой.
Виестурс
@Viesturs Это суть проблемы, да.
Кусалананда
1
Для подстроки поиска должно быть *"$testseq"*для caseкак для [[...]](за исключением Zsh , если не включить globsubst)
Stéphane Chazelas
Проще чем [ "${str##*substr*}" ] || echo True?
Исаак
@Isaac С точки зрения чтения и понимания происходящего, да. Также легко продлить один тест несколькими тестовыми примерами, не получая спагетти «если-то-элиф-то-элиф». Хотя тестирование одной строки, как вы показываете (исчезает ли строка в подстановке) , короче.
Кусалананда
1

Для переносимого способа проверить, содержит ли строка подстроку, используйте:

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

[ "${file##*$testseq*}" ] || echo True Substring is present

Или "${file##*"$testseq"*}"чтобы не интерпретировать символы глобуса в testseq.

Исаак
источник