Поиск подстроки без учета регистра в скрипте оболочки [закрыто]


22

Как я могу написать сценарий оболочки, который будет делать нечувствительное к регистру совпадение подстроки вывода команды?


grep -iможет быть?
Рамеш

Как я помещу это в мой сценарий? Извините, если это вопросы новичка. Я только начинаю изучать Linux, потому что он мне нужен для прохождения практики. Благодарность!
Мигель Рок

1
То, о чем вы спрашиваете, это сценарии оболочки - «linux» - это не язык программирования, а ядро ​​операционной системы. Оболочка, наиболее часто используемая с linux bash, является надмножеством стандарта unixsh . Вы можете начать с рассмотрения одного из них: | 1 | | 2 | - просто чтобы понять, что является фактическим контекстом.
Златовласка

1
Этот вопрос сейчас кажется вполне понятным и соответствует рекомендациям справочного центра. Можно ли его открыть для блага других?
BobDoolittle

2
Я не вижу неясности, почему этот вопрос не ясен. Что я должен добавить, чтобы это было понятно?
Мигель Роке

Ответы:


11

Сначала вот простой пример скрипта, который не игнорирует регистр:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Попробуйте изменить строку hello справа, и она больше не должна отображаться it works. Попробуйте заменить echo helloна команду по вашему выбору. Если вы хотите игнорировать регистр, и ни одна из строк не содержит перенос строки, вы можете использовать grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

Ключевым моментом здесь является то, что вы передаете выходные данные команды grep. ifЗаявление проверяет статус выхода из крайней правой команды в трубопроводе - в этом случае Grep. Grep успешно завершает свою работу тогда и только тогда, когда находит совпадение.

-iВариант Grep говорит игнорировать регистр. Вариант говорит не веет выход и выход после первого матча. Вариант говорит , чтобы рассматривать аргумент в виде строки , а не регулярное выражение.
-q
-F

Обратите внимание, что в первом примере используются прямые сравнения и различные полезные операторы. Вторая форма просто выполняет команды и проверяет их состояние выхода.[ expression ]


Я не понимаю, почему Жиль счел необходимым изменить код, который я внес. Он ничего не сломал, но он работал просто отлично. В этом примере вам не нужны двойные кавычки - они важны, если выходные данные содержат пробелы. И == работает так же хорошо, как и =, потому что sh на самом деле bash в Linux. Оригинальный Bourne Shell давно ушел на данный момент. Я не думаю, что даже Solaris отправляет это больше. Хотя в этом примере и нет необходимости, я согласен с тем, что двойные кавычки, вероятно, являются наилучшей практикой, но, по моему мнению, '==', чтобы разделение назначения и сравнения было четко разделено.
BobDoolittle

Подождите, так можно редактировать сообщение? Я не знал этого.
Мигель Роке

С достаточной репутацией, да. Я надеюсь, что кто-то с высокой репутацией подумает дважды, прежде чем вносить ненужные изменения, особенно для написания кода на этом форуме. unix.stackexchange.com/help/privileges
BobDoolittle

@BobDoolittle В некоторых случаях это может иметь значение, но не с вашей настройкой - это полезно знать.

2
Обратите внимание, что на практике речь идет не только о оболочке Bourne. ==это не POSIX. shне bashна всех системах на основе Linux. ==не поддерживается ash(на чем shоснованы многие BSD и производные Debian по крайней мере), или posh, и потребности указаны в zsh. Там нет смысла удваивать =. [это команда для тестирования. Нет необходимости делать разногласия между назначением и сравнением здесь. Это отличается от (( a == b ))против (( a = b)). Использование ==в сценарии, которое начинается с #! /bin/sh, неправильно. Если вы предполагаете kshили bashсинтаксис, обновите #!соответственно.
Стефан Шазелас

49

Вы можете выполнить подстроку без учета регистра, bashиспользуя собственно оператор regex, =~если вы установили nocasematchопцию оболочки. Например

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match

6
смешно! очки за неясные знания оболочки.
BobDoolittle

2
Эта опция также влияет на оператор простого совпадения. [[ XYZ == xyz ]] && echo "match"=>match
itadok

7

Для поиска строки с учетом регистра значения переменной needleв значении переменной haystack:

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Для поиска строки без учета регистра конвертируйте оба в один и тот же регистр.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Обратите внимание, что tr coreutils в GNU не поддерживает многобайтовые локали (например, UTF-8). Чтобы работать с многобайтовыми локалями, используйте вместо этого awk. Если вы собираетесь использовать awk, вы можете сделать сравнение строк, а не только преобразование.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

tr BusyBox не поддерживает синтаксис; Вы можете использовать вместо этого. BusyBox не поддерживает локали, отличные от ASCII.[:CLASS:]tr a-z A-Z

В bash (но не sh) версии 4.0+ имеется встроенный синтаксис для преобразования регистра и более простой синтаксис для сопоставления строк.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac

Я понимаю, что это пара лет, но все это printf | trзаставляет мою голову кружиться. Там, где это возможно, сводите вызов команд к минимуму ... учитывая переменную v, вы можете выполнить то же самое, используя v=$(tr '[:lower:]' '[:upper:]' <<<$v). Для тех, кто никогда не видел его раньше, по <<<сути это «переменная здесь», как использование <<EOFдля документа здесь. Не делайте этого printfили echoесли только вы абсолютно не обязаны это делать.
Будет

@Will Это работает только в оболочках, у которых есть <<<оператор: ksh, bash, zsh, но не обычный sh. И это довольно близко к трубопроводу с printfточки зрения того, как он работает: там одинаковое количество вызовов forkи execve(при условии, что printfоно встроено, что имеет место в большинстве распространенных оболочек); Разница в том, что <<<вместо временного канала создается временный файл. <<<удобно набирать, но не улучшение производительности.
Жиль "ТАК - перестань быть злым"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.