Пошук нечутливих до регістру підрядків у сценарії оболонки [закрито]


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

Спробуйте змінити рядковий привіт праворуч, і це більше не повинно лунати it works. Спробуйте замінити echo helloна обрану вами команду. Якщо ви хочете ігнорувати регістр, і жоден рядок не містить розрив рядка, ви можете використовувати grep:

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

Ключовим тут є те, що ви переносите командний вихід grep. Оператор ifперевіряє стан виходу крайньої правої команди в конвеєрі - в цьому випадку grep. Греп виходить з успіхом, якщо і тільки якщо він знайде відповідність.

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

Зверніть увагу, що перший приклад використовує, що дозволяє здійснювати прямі порівняння та різні корисні оператори. Друга форма просто виконує команди та перевіряє їх статус виходу.[ expression ]


Я не розумію, чому Джілз вважав за необхідне змінити кодекс, який я вніс. Він нічого не зламав, але це спрацювало чудово. У цьому прикладі вам не потрібні подвійні лапки - вони важливі, якщо на виході є пробіли. І == працює так само добре, як = тому, що sh насправді баш в Linux. Оригінальний Борн Шелл уже давно минув. Я не думаю, що навіть Solaris вже не відправляє це. Хоча в цьому прикладі непотрібно, я погоджуюся, що подвійні цитати, мабуть, є найкращою практикою, але, на мій погляд, це так і є "==", щоб присвоєння та порівняння було чітко відокремленим.
BobDoolittle

Зачекайте, щоб ви могли редагувати публікацію? Я не знаю, що.
Мігель Роке

Маючи достатню репутацію, так. Я сподіваюся, що хтось із високою репутацією подумає двічі, перш ніж робити непотрібні зміни, особливо, щоб кодувати на цьому форумі. unix.stackexchange.com/help/privileges
BobDoolittle

@BobDoolittle У певних випадках це може змінитися, але не в налаштуваннях - це добре знати.

2
Зауважте, що на практиці йдеться не лише про оболонку Борна. ==не є 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в GNU coreutils не підтримує багатобайтові локалі (наприклад, UTF-8). Щоб зробити роботу з багатобайтовими локалями, використовуйте натомість awk. Якщо ви збираєтеся використовувати awk, ви можете змусити його робити порівняння рядків, а не лише перетворення.

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

The 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.