Символ двоеточия портит мое соответствие образца в Bash

Если ваш grep поддерживает PCRE, вы можете:

grep -Po '^Hello \K[^ ]+(?= )' hi.html

Чтобы сохраните его в переменной:

myvariable="$(grep -Po '^Hello \K[^ ]+(?= )' hi.html)"

Альтернативный sed способ:

sed -n 's/^Hello \([^ ]\+\) .*/\1/p' hi.html

Чтобы сохранить его в myvariable :

myvariable="$(sed -n 's/^Hello \([^ ]\+\) .*/\1/p' hi.html)"

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

1
06.01.2019, 14:26
2 ответа

Вы должны удалить \перед :во втором тесте, иначе он попытается сопоставить буквальный символ \.

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

Я предполагаю, что вы хотели бы извлечь 20 из двух первых строк и сохранить их в devReadErr, но не тогда, когда строка читается как READ: DISABLED. Это именно то, что делает ваш код, если удалить \:

if  [[ ${line} == *"RAW_READ_ERROR_RATE"* ]] ||
    [[ ${line} == "READ:"* ]] &&
    [[ ${line} != *"READ: DISABLED"* ]]; then

    devReadErr=$(echo "$line" | awk '{print $2}')

fi

Другой способ сделать то же самое:

if [[ "$line" != *'DISABLED' ]]; then
    devReadErr=${line##* }
fi

Это извлекает число как строку после последнего символа пробела в $line, если строка не заканчивается словом DISABLED. Это позволяет избежать echoи awk.

Если это часть более крупного цикла, который анализирует файл построчно, то я бы предложил написать его на awkили другом языке, предназначенном для анализа текста. См., например, Почему использование цикла оболочки для обработки текста считается плохой практикой? .

3
27.01.2020, 23:31

Я подозреваю, что ты хочешь:

if [[ $line = *RAW_READ_ERROR_RATE* || 
      $line = READ:* && $line != *"READ: DISABLED"* ]]; then

Оператор&&[[...]]имеет приоритет над ||, но оператор оболочки&&имеет тот же приоритет, что и ||.

Или сделать это явным:

if [[ $line = *RAW_READ_ERROR_RATE* || 
      ($line = READ:* && $line != *"READ: DISABLED"*) ]]; then

Или используя операторы оболочки &&/ ||и несколько [[...]]s:

if [[ $line = *RAW_READ_ERROR_RATE* ]] || { 
      [[ $line = READ:* ]] && [[ $line != *"READ: DISABLED"* ]]; }; then

Или изменить порядок:

if [[ $line = READ:* ]] && [[ $line != *"READ: DISABLED"* ]] ||
   [[ $line = *RAW_READ_ERROR_RATE* ]]; then

Или используйте шаблон, который соответствует всем:

if [[ $line = @(*RAW_READ_ERROR_RATE*|!(!(*READ:*)|*READ:\ DISABLED*)) ]]; then

Без скобок/фигурных скобок ваше читается как:

if [[ ($line = *RAW_READ_ERROR_RATE* || 
     $line = READ:*) && $line != *"READ: DISABLED"* ]]; then

Это не должно мешать ему сопоставлять строки, содержащие RAW_READ_ERROR_RATE, но при условии, что они не содержат READ: DISABLED.

0
27.01.2020, 23:31

Теги

Похожие вопросы