Як порівняти рядки в Bash


957

Як порівняти змінну з рядком (і зробити щось, якщо вони збігаються)?



Відповіді:


1372

Використання змінних у операторах if

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

Якщо ви хочете щось зробити, коли вони не відповідають, замініть =на !=. Докладніше про струнні операції та арифметичні операції ви можете прочитати у відповідній документації.

Чому ми використовуємо цитати навколо $x?

Ви хочете, щоб лапки були навколо $x, тому що якщо він порожній, ваш сценарій Bash стикається з синтаксичною помилкою, як показано нижче:

if [ = "valid" ]; then

Нестандартне використання ==оператора

Зауважте, що Bash дозволяє ==використовувати для рівності [, але це не є стандартом .

Використовуйте або перший випадок, коли лапки навколо $xнеобов’язкові:

if [[ "$x" == "valid" ]]; then

або використовувати другий випадок:

if [ "$x" = "valid" ]; then

12
Як це стосується прийнятої відповіді, наведеної в Несподіваній помилці оператора ? Я отримав таку ж помилку при використанні [ "$1" == "on" ]. Змінивши це на ["$ 1" = "on"] проблему вирішено.
Пьотр Доброгост

78
Пробіли потрібні.
TAAPSogeking

6
@JohnFeminella При написанні баш-сценарію у нього повинно бути один, =а не два.
користувач13107

72
можливо, варто відзначити, що ви не можете користуватися [ $x -eq "valid" ]. -eqє оператором порівняння для цілих чисел, а не рядків.
craq

2
@ Алекс, У яких випадках (якщо взагалі колись) мені потрібно використовувати шаблон ["x$yes" == "xyes"], тобто префікс як змінної, так і літерального рядка з x? Це реліквія старих часів чи вона справді потрібна в деяких ситуаціях?
lanoxx

142

Або, якщо вам не потрібно іншого пункту:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

71
І якщо вам потрібен інший пункт, і ви хочете зробити божевільний однолінійний текст: ["$ x" == "дійсний"] && echo "дійсний" || відлуння "недійсне"
Метт Уайт

11
@MattWhite: це, як правило, погана ідея, оскільки echoможе провалитися.
gniourf_gniourf

1
навіть ті, що можуть здатися, красивими та вишуканими способами як від marko && MattWhite
Deko

3
@gniourf_gniourf, немає проблем, використовуй [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123

4
@ 12431234123412341234123 { echo invalid && false; }ефективніше ( echo invalid && false ), тому що дозволяє уникнути оплати за непотрібну передплату.
Чарльз Даффі

84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

Примітки:

  1. Проміжки між ifі [та ]є важливими
  2. >і <оператори перенаправлення так уникнути його \>і , \<відповідно , для рядків.

6
Дякую за порівняння в алфавітному порядку
shadi

Моя проблема полягала в тому, що $aнасправді вона " "оточувала його як частину буквеного значення рядка, тому мені довелося використовувати символ утечі, $bщоб порівняти значення. Мені вдалося знайти це після запуску bash -x ./script.sh, прапор -x дозволяє бачити значення кожного виконання і допомагає в налагодженні.
ShahNewazKhan

Зауважте, що порівняння в алфавітному порядку не є стандартизованим POSIX, тому не гарантується, що він працює на платформах, що не належать до GNU / без оболонок. Тільки операції в pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html гарантуються як портативні.
Чарльз Даффі

62

Для порівняння рядків із символами підстановки

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi

12
Важливо, щоб макіяж використовував лише праворуч! Також зауважте, що відсутні "навколо символів. (btw: +1 для
макетів

6
Розширення $stringB повинно бути укладено в лапки (і, до речі, ліва рука не повинна бути вказана): if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf

Я намагаюся використовувати ту саму логіку підстановки для імені файлу на шляху до файлу. Але це не працює для мене. спробував усі наведені тут різні рядки. але це завжди йде в іншому випадку. stringA у моєму випадку - це шлях до файлу / tmp / file, а stringB - "файл".
дощ

35

Я повинен погодитися з одним із коментарів в одному пункті:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Ні, це не шалений онлайнер

Це просто схоже на одного, хм, непосвяченого ...

Він використовує загальноприйняті зразки як мову, певним чином;

І після того, як ви засвоїли мову.

Власне, приємно читати

Це простий логічний вираз з однією особливою частиною: лінива оцінка логічних операторів.

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Кожна частина є логічним виразом; перший може бути правдивим або хибним, два інших завжди правдивими.

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

Тепер, коли вона оцінюється, перевіряється перша. Якщо він хибний, то другий операнд логіки і && після нього не має значення. Перше не відповідає дійсності, тому воно не може бути першим, а друге - істинним.
Тепер у цьому випадку перша сторона логіки чи || помилкова, але це може бути правдою, якщо інша сторона - третя частина - є правдою.

Тож буде оцінена третя частина - в основному написання повідомлення як побічний ефект. (Він має результат 0для істини, яку ми тут не використовуємо)

Інші випадки схожі, але простіші - і - обіцяю! є - можна - легко читати!
(У мене його немає, але я думаю, що ветеран UNIX із сірою бородою дуже допомагає в цьому.)


17
... && ... || ...Зазвичай несхвально (вибачте глиняний глечик Unix ветеран, ви були неправильно весь цей час), так як це не семантично еквівалентно if ... then ... else .... Не хвилюйтесь, це загальна проблема .
gniourf_gniourf

6
@ gniourf_gniourf OP не помиляється - і вони, ймовірно, не знають, як ви пропонуєте. ... && ... || ...- цілком дійсний зразок та загальна бадіозна ідіома. Її використання передбачає попередні знання (про що, можливо, варто пам’ятати, якщо в аудиторії є початківці), але ОП має волосся, щоб довести, що вони знають, як уникнути відкритих кришок люків.
ebpa

3
@ebpa Що робити, якщо оператор після && поверне значення false, буде виконано виконання до оператора, наступного за || ? Якщо так, це неправильно, і, можливо, те, що пропонує gniourf
TSG

4
Я думав, що відлуння - лише приклад. Виписка, що випливає з &&, може все-таки повернути ненульове значення
TSG

2
@gniourf_gniourf +1 для публікації посилання на Bash Pitfalls! Дуже корисний!
Ягуар

21

ви також можете використовувати case / esac

case "$string" in
 "$pattern" ) echo "found";;
esac

Це еквівалентність чи містить?
ytpillai

@ytpillai, це еквівалентність. Майте на увазі, що ви можете мати шаблони, розділені до |, перш ніж ). inЗатвердження еквівалентно thenв ifзвітності. Ви можете стверджувати, що він працює над списком шаблонів, де кожен список має власну декларацію, що робити, якщо ви родом з Python. Не як substring in string, а навпаки for item in list. Використовуйте *як останнє твердження, якщо ви хочете elseумови. Він повертається при першій зустрічі.
мазунки

18

Наступний скрипт читається з файлу з назвою "testonthis" рядок за рядком, а потім порівнює кожен рядок з простим рядком, рядком зі спеціальними символами та регулярним виразом. Якщо вона не збігається, сценарій надрукує рядок, інакше ні.

Простір у Баші настільки важливий. Отже, буде працювати наступне:

[ "$LINE" != "table_name" ] 

Але наступне не буде:

["$LINE" != "table_name"] 

Тому будь ласка, використовуйте так:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done

Використовуйте цей підхід для проходження файлу. Тобто, видалити UUoC серед іншого.
fedorqui 'ТАК перестаньте шкодити'

Це не важливо через, bashа тому [, що насправді є зовнішнім бінарним (як і в which [прибутковості щось подібне /usr/bin/[)
Патрік Бергнер

11

Можливо, я б скористався відповідниками regexp, якщо вхід містить лише кілька дійсних записів. Наприклад, лише "старт" і "стоп" є дійсними діями.

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

Зауважте, що я малу величину змінює $ACTION, використовуючи подвійні коми. Також зауважте, що це не буде працювати над занадто постареними баш-версіями.


9

Bash 4+ прикладів. Примітка: невикористання лапок спричинить проблеми, коли слова містять пробіли тощо. Завжди цитуйте в Bash, IMO.

Ось кілька прикладів у Bash 4+:

У прикладі 1 перевірте "так" у рядку (нечутливий до регістру):

    if [[ "${str,,}" == *"yes"* ]] ;then

Приклад 2, перевірте "так" у рядку (нечутливий до регістру):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Приклад 3, перевірте "так" у рядку (з урахуванням регістру):

     if [[ "${str}" == *"yes"* ]] ;then

У прикладі 4 перевірте "так" у рядку (з урахуванням регістру):

     if [[ "${str}" =~ "yes" ]] ;then

Приклад 5, точна відповідність (залежно від регістру):

     if [[ "${str}" == "yes" ]] ;then

Приклад 6: Точна відповідність (нечутливий до регістру):

     if [[ "${str,,}" == "yes" ]] ;then

Приклад 7, точна відповідність:

     if [ "$a" = "$b" ] ;then

Насолоджуйтесь.


для мене (mac GNU bash версія 4.4.12 (1) -випуск x86_64-apple-darwin17.0.0), я повинен використовувати if [ "$a"="$b" ]або він не працює ... не може бути пробілів навколо рівних
спектр

1

Я зробив це таким чином, що сумісний з Bash і Dash (sh):

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac

яка різниця між використанням попереднього (проти не використанням його?
мазунки
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.