LinuxForum.Fans
Тема

Регулярное выражение в bash

Автор: gaal_dev 12 сообщений 5704 просмотров
#163022

bash версии 4.1.5. Раньше в версии 3.x такое выражение работало:

text

if [[ $STRING =~ '^olcAccess:\s*{\d+}(.*)' ]]; then

Проверял тут http://gskinner.com/RegExr/ на строке olcAccess: {5}to attrs=mail и тд

В версии 4.x нужно указывать без одинарных и двойных кавычек - теперь они часть строки.

text

if [[ $STRING =~ ^olcAccess:\s*{\d+}(.*) ]]; then

Не работает. Странно. Попробовал экранировать { - не работает. Так тоже верно ^olcAccess:\s*\{\d+\}(.*).

Проверил для интереса на egrep - работает.

В чем может быть причина? Чего не хватает?

#163060
gaal.dev написал:
if [[ $STRING =~ ^olcAccess:\s*{\d+}(.*) ]]; then

1) \d это перл
2) надо экранировать \(, \), \{,\},\+
3) про \s точно не помню. но вроде в POSIX [[:space:]]

#163236
drBatty написал:
[quote=gaal.dev]if [[ $STRING =~ ^olcAccess:\s*{\d+}(.*) ]]; then

1) \d это перл
2) надо экранировать \(, \), \{,\},\+
3) про \s точно не помню. но вроде в POSIX [[:space:]][/quote]

То, что работало в 3.2.5 не всегда работает в 4.1.5:

Тестовые примеры:

text

#!/bin/bash

string=' 123 '

if [[ $string =~ \s*[0-9]+\s* ]]; then echo 'yes' else echo 'no' fi

Работает.

Ставлю кавычки:

text

#!/bin/bash

string=' 123 '

if [[ $string =~ '\s*[0-9]+\s*' ]]; then или так (if [[ $string =~ "\s*[0-9]+\s*" ]]; then) echo 'yes' else echo 'no' fi

Не работает. Ни одинарные, ни двойные - "\s*[0-9]+\s*", '\s*[0-9]+\s*' - не прокатывает.

В новой версии bash немного по-другому работает, но как именно? В документации не нашел.

До этого \s и по-моему \d тоже работало. По-видимому сейчас только POSIX или где-то совместимость настраивается. Записал окончательно так:

text

if [[ $string =~ ^olcAccess:[[:space:]]*\{[0-9]+\}(.*) ]]; then

В прежней версии работало и так

text

 if [[ "$STRING" =~ '(\s*)(\w+):(\s*)(.*)(\s*)' ]]; then

и так

text

if [[ "$string" =~ '(\s*)(.+)(\s*)\{([0-9]+)\}(\s*)(.+)(\s*)' ]]; then.
#163335
gaal.dev написал:
В новой версии bash немного по-другому работает, но как именно?

та откуда я знаю?! я никогда такого не применял, не применяю, и применять не намерен. Эти [[ с регулярками всю жизнь криво работали. Вот так пишу:

text
#!/bin/bash

string=' 123 '

if echo "$string" | grep -Eq '\s*[0-9]+\s*'; then echo 'yes' else echo 'no' fi

а привычка писать без кавычек регулярки - это вообще стиль камикадзе - никогда не знаешь, куда и как кто это первый распарсит :(

#163345
drBatty написал:

та откуда я знаю?!

это, если кто знает :)

насколько понял теперь надо использовать символьные классы POSIX:

http://ru.wikipedia.org/wiki/Представление_символов_в_регулярных_выражениях#.D0.A1.D0.B8.D0.BC.D0.B2.D0.BE.D0.BB.D1.8C.D0.BD.D1.8B.D0.B5_.D0.BA.D0.BB.D0.B0.D1.81.D1.81.D1.8B_POSIX

http://ru.wikipedia.org/wiki/Regex#.D0.A0.D0.B0.D1.81.D1.88.D0.B8.D1.80.D0.B5.D0.BD.D0.BD.D1.8B.D0.B5_.D1.80.D0.B5.D0.B3.D1.83.D0.BB.D1.8F.D1.80.D0.BD.D1.8B.D0.B5_.D0.B2.D1.8B.D1.80.D0.B0.D0.B6.D0.B5.D0.BD.D0.B8.D1.8F_POSIX

возможно поддержка перловых отключена, так собран пакет - включается при компиляции, либо еще что-то, поэтому не работает с \s и т.д..

drBatty написал:

Вот так пишу

мне нужно было значение группы в скобках - подстрока. потом можно обращаться через BASH_REMATCH по индексу. нулевой элемент вся строка, первый - первая группа и т.д.

BASH_REMATCH
An array variable whose members are assigned by the ‘=~’ binary operator to the [[ conditional command (see Conditional Constructs). The element with index 0 is the portion of the string matching the entire regular expression. The element with index n is the portion of the string matching the nth parenthesized subexpression. This variable is read-only.

drBatty написал:

а привычка писать без кавычек регулярки - это вообще стиль камикадзе - никогда не знаешь, куда и как кто это первый распарсит :(

в новой версии 4.x так нельзя в операторе поиска по шаблону =~

http://www.gnu.org/software/bash/manual/bash.html

shopt [-pqsu] [-o] [optname ...]

compat31
If set, Bash changes its behavior to that of version 3.1 with respect to quoted arguments to the conditional command's =~ operator.

#163353
gaal.dev написал:
возможно поддержка перловых отключена, так собран пакет - включается при компиляции, либо еще что-то, поэтому не работает с \s и т.д..

в мане написано, что надо читать что пишут в libc, а точнее в man 3 regex, ибо именно оттуда берутся регулярки. В моей libc \s работает, а вот \d - нет. Насколько я знаю, это по POSIX-стандарту. С другой стороны, нужно понимать, что в POSIX нет UTF-8, потому мы пролетаем с нашим Великим и Могучим. Что ессно недопустимо. Потому glibc не совсем POSIXовая.

Естественно, ваша версия bash может использовать и свои регулярки, как и другие утилиты. Зависит это от опций компиляции.

Патрик наложил 10 патчей на bash, а ваши маинтейнеры наверняка ещё больше. Потому очень сложно хоть как-то прогнозировать поведение в этом случае. Ещё раз рекомендую использовать более предсказуемые утилиты.

gaal.dev написал:
мне нужно было значение группы в скобках - подстрока. потом можно обращаться через BASH_REMATCH по индексу. нулевой элемент вся строка, первый - первая группа и т.д.

[console]$ echo ' 123 ' | sed -r 's/\s*([0-9]+)\s*/"\1"/'
"123"
[/console]

gaal.dev написал:
в новой версии 4.x так нельзя в операторе поиска по шаблону =~

не вдавался.

#163442

[console]
$ echo ' 123 ' | sed -r 's/\s*([0-9]+)\s*/"\1"/'
"123"
[/console]

Только обычно так перенаправляю в файл. И так можно только одну подстроку извлечь.

drBatty написал:

Естественно, ваша версия bash может использовать и свои регулярки, как и другие утилиты. Зависит это от опций компиляции.

Вот это и хочу проверить.

#163443
gaal.dev написал:

1)Только обычно так перенаправляю в файл.
2)И так можно только одну подстроку извлечь.

1) нет. не обязательно.
2) нет. можно \0 \1 \2 \3 \4 \5 \6 \7 \8 \9

gaal.dev написал:
Вот это и хочу проверить.

зря. я пишу такие скрипты, которые работают на любых серверах. Ваши будут работать только на некоторых. Это минус.

#163451
drBatty написал:
[quote=gaal.dev]
1)Только обычно так перенаправляю в файл.
2)И так можно только одну подстроку извлечь.

1) нет. не обязательно.
2) нет. можно \0 \1 \2 \3 \4 \5 \6 \7 \8 \9

gaal.dev написал:
Вот это и хочу проверить.

зря. я пишу такие скрипты, которые работают на любых серверах. Ваши будут работать только на некоторых. Это минус.[/quote]

> 2) нет. можно \0 \1 \2 \3 \4 \5 \6 \7 \8 \9

В принципе можно и так :)

echo '123 xyz 456' | sed -r 's/\s*([0-9]+)\s*[[:alpha:]]+\s*([0-9]+)/\1\n\2/'
123
456

echo '123 xyz 456' | sed -r 's/\s*([0-9]+)\s*[[:alpha:]]+\s*([0-9]+)/"\1"\n"\2"/'
"123"
"456"

Мне больше =~ нравится и BASH_REMATCH как встроенное в BASH.

Любопытно. На машине два дистрибутива. Хочу проверить различия.

\s не по POSIX. http://phpclub.ru/detail/article/simple_regular У меня из-за этого выражение не срабатывало. Написал [[:space:]] - заработало.

Часть 3: PCRE

И вот, наконец, серия выпусков про регулярные выражения подходит к концу. Поговорим о регулярных выражениях совместимых с Perl (Perl compatible regular expressions — PCRE).

\s [ ]

#163452
gaal.dev написал:
Мне любопытно. На машине два дистрибутива. Хочу проверить различия.

ну а у меня работа. мне надо чтобы работало. за это деньги платят. остальное нии...т. Такие дела.

#163453
drBatty написал:
[quote=gaal.dev]Мне любопытно. На машине два дистрибутива. Хочу проверить различия.

ну а у меня работа. мне надо чтобы работало. за это деньги платят. остальное нии...т. Такие дела.[/quote]

Один дистр федора, другой мандрива. В первой версия 3.x, во второй 4.x. Сверялся, если что-то не работало. До этого работало, теперь нет - переписываю теперь под POSIX. В прочем ничего страшного - программа установки была под дистр.

Да. Лучше придерживаться под bash POSIX. В федоре pcre работает в 3.x, а в мандриве не работает в 4.x. (Perl compatible regular expressions — PCRE)

#163460

gaal.dev, как хотите.

Войдите или зарегистрируйтесь, чтобы ответить.