Grep 正規表示式結果不符合預期?

Grep 正規表示式結果不符合預期?

使用 FreeBSD 11.1:

#!/bin/sh

if printf 'abcde.fgh' | grep -iEq '^[^][$^*_-]'; then
    echo "test 1 success"
else
    echo "test 1 fail"
fi

echo

if printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'; then
    echo "test 2 success"
else
    echo "test 2 fail"
fi

輸出:

test 1 success

grep: Unmatched [ or [^
test 2 fail

但 AFAICT 這些應該會給出相同的結果。它們都包含第一個字元(僅)的條件,即它不是指定的非字母字元清單之一。正規表示式的細分:

  • ^= 字串的開頭
  • [^...]= 如果沒有這些字元則匹配
  • 在列表中,]必須是第一個字符,^不能是第一個字符,並且 - 必須是最後一個字符。][.^$_-有效的文字字元清單也是如此,且字串不得與其中任何一個相符。
  • 為了避免混淆,請注意,這意味著清單中的][文字"]"和字符,"["不是關閉並重新開啟 2 個清單。

兩個表達式之間的唯一區別是"."但它位於列表內,因此應將其視為not literal .並且實際上第一個字元與文字不匹配"."

我缺什麼?可能是一些非常明顯和簡單的事情?

答案1

您缺少一些其他語法規則。在括號擴展中,除了普通範圍之外,還有幾種以 . 開頭的多字元表達式[。 (參見正規表示式(7)手冊用於Linux或者自由BSD在「除了這些以及一些使用“[”的組合(參見下一段)」。)這些是:

  • 整理元素:[.....]
  • 等價類:[=...=]
  • 字元類別:[:...:]

(您可能已經看到或使用過這樣的表達式[[:digit:]]- 這些實際上是一個字元類[:digit:],恰好是[…]括號擴展的唯一元素。)

因此,在您的情況下,由於 恰好.緊接在 a 之後[,因此它們被識別為整理元素的開始分隔符號。 GNU grep 3.1 有正確的錯誤訊息:

$ printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'
grep: Unmatched [, [^, [:, [., or [=

可以使用相同的表達式來逃避這種情況,方法是使用例如[...][=.=]來包含常規點,或類似地[=-=]匹配破折號(如果沒有地方可以移動它們)。

相關內容