Перевірте, чи містить рядок підрядку


40

У мене є код

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". Як це могло бути? Як виправити проблему?


Відповіді:


25

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

  • $file == *_"$testseq"_*(тут $testseqрозглядається як фіксований рядок)

  • $file == *_${testseq}_*(тут $testseqрозглядається як візерунок).

Або _одразу після того, як ім’я змінної буде прийнято як частину імені змінної (це дійсний символ у назві змінної).


Правильна відповідь, як це стосується ОП, але без переносу. (Це не критика наданої відповіді, а лише попередження читачів). ;-)
Cbhihe

28

Використовуйте =~оператор для регулярного порівняння виразів:

#!/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_та а *". Змінна $testseq_не визначена, тому вона буде розширена до порожнього рядка, і ви закінчите *_*, що, очевидно, відповідає $fileзначенню, яке ви маєте. Ви можете розраховувати на отримання True, поки ім'я файлу в$file містить хоча б одну підкреслення.

Для того, щоб правильно розмежувати ім'я змінної, використання "..."навколо розширення: *_"$testseq"_*. Це використовувало б значення змінної у вигляді рядка. Чи хочете ви використовувати значення змінної як візерунок , використовуйте *_${testseq}_*замість цього.

Ще одне швидке виправлення - включити підкреслення у значення $testseq :

testseq="_gen_"

а потім просто використовувати *"$testseq"*як зразок (для порівняння рядків).


Тож оболонка буде шукати змінну $ testseq_, а не знаходити її та замінювати її порожнім рядком.
Вієстур

@Viesturs Це суть проблеми, так.
Kusalananda

1
Для пошуку підрядків це має бути *"$testseq"*на caseзразок for [[...]](крім zsh, якщо ви не включите globsubst)
Stéphane Chazelas,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.