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