Могу ли я сохранить оценку выражения регулярного выражения в переменной? - PullRequest
2 голосов
/ 20 марта 2019

Я получаю строку, которая может быть либо полностью числовой, разделенной дефисом, и в этом случае она будет приемлемой для меня (например, 123423-56788-456522-34245), либо не полностью числовой и все еще разделенной дефисомв этом случае это неприемлемо для меня (например, 123423-56788-shelve-34245).

Чтобы определить, является ли строка приемлемой, я построил следующий блок if:

REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS='^[0-9-]+$'
if [[ ${BUILD_ID} =~ ${REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS} ]]
then
    echo true
else
    echo false
fi 

Вышеприведенный блок if работает нормально.Однако, если бы я программировал на другом языке (например, Java), я бы назначил оценку непосредственно в переменную.Например:

int a = 3; 
int b = 5; 
boolean test = (a < b);

Выше test будет true: я буду оценивать выражение (a < b) и сохранять его результат в переменной test в одной строке.

Я хотел бы знать, возможно ли сделать то же самое в Bash.Оглядываясь в Интернете, я не нашел много примеров.Благодаря этому ответу я понял, что если я сделаю это:

bash$ false_expression=$((2 == 4))
bash$ true_expression=$((2 == 2))

... две переменные принимают значения 0 и 1 соответственно.Это не совсем true или false, но я все еще могу это принять.Однако я не могу сделать то же самое с моим выражением, потому что, если я сделаю это:

InvalidCL=123423-56788-shelve-34245
MyRegex='^[0-9-]+$'
FalseExpression=$((${InvalidCL} =~ ${MyRegex}))

... третье назначение вызовет эту ошибку:

-bash: 123423-56788-shelve-34245 =~ ^[0-9-]+$: attempted assignment to non-variable (error token is "=~ ^[0-9-]+$")

Я не настоящий эксперт по bash, поэтому мой вопрос (надеюсь, это не слишком глупо): возможно ли присвоить оценку переменной? Я вижу, что мой if [[ myExpression ]] оценивается какtrue, поэтому я не понимаю, почему я не смогу присвоить эту оценку переменной ... Кто-нибудь может объяснить, пожалуйста?

Ответы [ 4 ]

3 голосов
/ 20 марта 2019

Если вы действительно хотите сделать это с одним назначением, вы можете сделать это следующим образом:

FalseExpression=$( [[ "$InvalidCL" =~ $MyRegex ]] && echo 1 || echo 0)

, где 1 означает true и 0 для false.Имейте в виду, однако, что это не традиционный способ Bash.Результат 0 в Bash указывает на отсутствие ошибки, т. Е. Если выражение оценивается как true, то вы получите состояние выхода:

$ echo $?
0

Обратите внимание, использование одного (, который стоитдля подстановки команд, тогда как (( в вашем примере вычисляет математическое выражение.

Традиционно, вероятно, это можно сделать так:

$ [[ "$InvalidCL" =~ $MyRegex ]]
$ FalseExpression=$?

Bash хранит состояние выхода последнегооперация в $?, которая ведет себя противоположно оператору $(()).Если выражение true, то $? сохранит 0, а $ (()) вернет 1.Последнее, вероятно, более знакомо, если вы пришли из Си фона.Я предлагаю не смешивать эти подходы.Отладка сценария может быть довольно сложной, если один результат может иметь разные значения.

1 голос
/ 20 марта 2019

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

Что касается формулировки фактического вопроса, я хотел бы отметить, чторезультаты оценки выражения регулярного выражения фактически автоматически сохраняются в переменной окружения в bash.В массиве $BASH_REMATCH все совпадения хранятся в индексе 0, а группы захвата - в соответствующих индексах.См .: https://www.linuxjournal.com/content/bash-regular-expressions

Количество элементов в этом массиве может также, возможно, более удобно, чем ручное назначение из $?, использоваться в качестве индикатора успеха матча.Если ${#BASH_REMATCH[*]} равно нулю, последнее регулярное выражение не соответствует.

Вы получаете сообщение об ошибке, которое вы цитировали, поскольку синтаксис соответствия регулярному выражению определен только в конструкции [[ ... ]], а не в $(( ... )) арифметической оценкепоэтому, когда он видит =, он думает, что вы пытаетесь выполнить какое-то задание.

1 голос
/ 20 марта 2019

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

I настоятельно рекомендуем добавить несколько пояснительных комментариев к этому.

# assign an integer BOOLEAN value from the test for a match
# the ! means NOT, inverts a 0/1 OS exit code from [[ ]]
match="$( [[ ! "$string" =~ $pattern ]]; echo $?; )"  
# now $match is 1 (TRUE) if it *matched* the pattern

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

boolMatch() { 
   local match str="$1" pat="$2"

   # test the match
   [[ "$str" =~ $pat ]]

   # invert the return to a boolean value
   match=$(( ! $? ))

   # pass back the boolean
   echo $match
}

$: boolMatch foo bar
0
$: boolMatch foo foo
1
$: match=$( boolMatch $stringToCheck $patternToUse )
1 голос
/ 20 марта 2019

Вы также можете сделать:

[[ ${BUILD_ID} =~ ${REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS} ]]
val=$?

, чтобы не вызывать подоболочку. И снова val равен 0 при успехе и 1 при неудаче.

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