Как сравнить строки в Bash

Ответы:

1377

Использование переменных в операторах 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 При написании в bash-скрипте он должен иметь один, =а не два.
user13107
73
возможно, стоит отметить, что вы не можете использовать [ $x -eq "valid" ]. -eqявляется оператором сравнения целых чисел, а не строк.
Craq
2
@ Алекс, В каких случаях (если когда-либо) мне нужно использовать шаблон ["x$yes" == "xyes"], то есть префикс переменной и строкового литерала с x? Это пережиток старины или он действительно нужен в некоторых ситуациях?
Lanoxx
142

Или, если вам не нужно еще пункт:

[ "$x" == "valid" ] && echo "x has the value 'valid'"
Marko
источник
71
И если вам действительно нужно предложение else и вы хотите создать сумасшедший однострочный текст: ["$ x" == "valid"] && echo "valid" || эхо "недействительно"
Мэтт Уайт
11
@MattWhite: обычно это плохая идея, так как echoможет потерпеть неудачу.
gniourf_gniourf
1
Даже если у вас могут быть и прекрасные, и элегантные способы от Марко и Мэтта Уайта
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
Спасибо за сравнение строки в алфавитном порядке
Шади
Моя проблема заключалась в том, что на $aсамом деле " "окружение было частью строкового литерала, поэтому мне пришлось использовать escape-символ $bдля сравнения значений. Я смог найти это после запуска bash -x ./script.sh, флаг -x позволяет увидеть значение каждого выполнения и помогает в отладке.
ShahNewazKhan
Обратите внимание, что сравнение в алфавитном порядке не стандартизировано POSIX, поэтому не гарантируется работа на платформах без GNU / без bash. Только операции на pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html гарантированно будут переносимыми.
Чарльз Даффи
62

Для сравнения строк с подстановочными знаками используйте

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi
Джеффри Л. Робертс
источник
12
Важно, чтобы подстановочные знаки можно было использовать только с правой стороны! Также обратите внимание на пропавшие "символы подстановки. (кстати: +1 для подстановочных знаков!)
Scz
6
Расширение $stringB должно быть заключено в кавычки (и, кстати, левая рука не должна быть указана): if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf
я пытаюсь использовать ту же логику подстановочных знаков для имени файла в пути к файлу. Но это не работает для меня. перепробовал все различные подстановочные строки, представленные здесь. но это всегда идет в другом случае. В моем случае строка A - это путь к файлу / tmp / file, а строка B - это «файл».
дождь
35

Я должен не согласиться с одним из комментариев в одной точке:

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

Нет, это не сумасшедший

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

Он использует общие шаблоны как язык, в некотором смысле;

И после того, как вы выучили язык.

На самом деле, приятно читать

Это простое логическое выражение, состоящее из одной специальной части: ленивая оценка логических операторов.

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

Каждая часть является логическим выражением; первое может быть истинным или ложным, два других всегда истинны.

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

Теперь, когда оно оценивается, проверяется первое. Если оно ложно, то второй операнд логики и && после него не актуален. Первое не соответствует действительности, поэтому оно не может быть первым, а второе, в любом случае, верно.
Теперь, в данном случае это первая сторона логики или || ложь, но это может быть правдой, если другая сторона - третья часть - верна.

Таким образом, третья часть будет оценена - в основном, написание сообщения в качестве побочного эффекта. (У него есть результат 0для истины, который мы здесь не используем)

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

Volker Siegel
источник
17
Обычно это ... && ... || ...вызывает недовольство (извините, седовласый ветеран Unix, вы все время ошибались), поскольку это не семантически эквивалентно if ... then ... else .... Не волнуйтесь, это распространенная ошибка .
gniourf_gniourf
6
@gniourf_gniourf OP не ошибается - и они, вероятно, не знают, как вы предлагаете. ... && ... || ...это совершенно правильный шаблон и общая идиома bash. Его использование действительно предписывает предварительные знания (что может быть полезно иметь в виду, если в аудитории есть новички), но у ОП есть шанс доказать, что они знают, как избегать открытых крышек люков.
ebpa
3
@ebpa Что если оператор, следующий за &&, возвращает значение false, выполнение будет продолжено до оператора, следующего за || ? Если это так, то это неправильно и, возможно, именно это предлагает gniourf
TSG
4
Я думал, что эхо было только примером. Оператор, следующий за &&, может по-прежнему возвращать ненулевое значение
TSG
2
@gniourf_gniourf +1 за размещение ссылки на Bash Pitfalls! Очень полезный!
Ягуар
21

Вы также можете использовать вариант использования / ESAC

case "$string" in
 "$pattern" ) echo "found";;
esac
ghostdog74
источник
Это эквивалентность или содержит?
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
Harshil
источник
Используйте этот подход для просмотра файла. То есть удалите UUoC среди прочего.
Федорки 'ТАК прекрати вредить'
Это не важно из-за, bashно потому что [это на самом деле внешний двоичный файл (как в случае с which [чем-то вроде /usr/bin/[)
Патрик Бергнер
11

Я бы, вероятно, использовал регулярные выражения, если на входе есть только несколько допустимых записей. Например, только «старт» и «стоп» являются допустимыми действиями.

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

Обратите внимание, что я строчные буквы переменной $ACTION, используя двойные запятые. Также обратите внимание, что это не будет работать на слишком старых версиях bash.

steviethecat
источник
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
shades3002
источник
какая разница между использованием предыдущего и (неиспользованием предыдущего ?
мазуньки