Регулярное выражение в скрипте bash

Регулярное выражение в скрипте bash

Это мой первый опыт написания bash-скриптов, поэтому я, вероятно, совершаю простую ошибку.

По сути, я пытаюсь написать скрипт, который получает группы пользователя, и если они находятся в определенной группе, он будет регистрировать это соответствующим образом. Очевидно, что будет больше функциональности, но нет смысла писать это, когда я даже не могу заставить работать регулярное выражение!

Пока что у меня вот что:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Везде, где я пробовал это регулярное выражение, оно работало. Но в скрипте bash оно выводит только $groups, за которым следует No match. Так может кто-нибудь сказать мне, в чем тут проблема?

решение1

От man 7 regex:

Выражение в квадратных скобках представляет собой список символов, заключенных в «[]». …

… Чтобы включить литерал «-», сделайте его первым или последним символом…. [В]се другие специальные символы, включая «\», теряют свое особое значение в выражении в квадратных скобках.

Попытка выполнить регулярное выражение с помощью egrep приводит к ошибке:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Вот более простая версия, которая также выдает ошибку:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

Так как \не является специальным, то есть диапазон, как и [a-z]было бы. Вам нужно поставить your -в конце, like [_-]или:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Это должно работать независимо от версии libc (в egrep или bash).

редактировать:На самом деле это зависит также от настроек локали. Страница руководства предупреждает об этом:

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

Например:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

Конечно, даже если это не ошибка, это не делает то, что вам нужно:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

Это диапазон, который в ASCII включает в себя \, [, ^, и _.

решение2

Общее правило для регулярных выражений (и любых ошибок в больших фрагментах кода): урезайте его и перестраивайте шаг за шагом или используйте деление пополам — что вам больше подходит.

В данном случае виновником оказался символ подчеркивания — экранирование его обратной косой чертой заставило его работать.

Связанный контент