shell測試多行字元串是否在最後一行包含指定的模式
我想確定多行字元串是否以包含指定模式的行結尾。
這些程式碼失敗,不匹配。
s=`echo hello && echo world && echo OK` [[ "$s" =~ 'OK$' ]] && echo match
在
bash
3.2 或更高版本中,如果未啟用與 3.1 的兼容性(使用compat31
選項 orBASH_COMPAT=3.1
),則引用正則表達式運算符(不僅與任何引用運算符 ( , , , ) 一起使用,\
而且與任何bash
引用運算符 ('...'
,"..."
,$'...'
,$"..."
) 一起使用)將刪除它們的特殊含義。[[ $var =~ 'OK$' ]]
僅在包含
OK$
字面的字元串中匹配($
匹配字面量$
)[[ $var =~ OK$ ]]
匹配以結尾的字元串
OK
(即匹配字元串末尾$
的 RE 運算符)。這也適用於儲存在變數中的正則表達式或某些替換的結果。
[[ $var =~ $regexp ]] # $var matches $regexp [[ $var =~ "$string" ]] # $var contains $string
請注意,它可能會變得很尷尬,因為您需要為 shell 語法引用一些字元(如空格、、、、、不匹配時的括號
<
)>
。&
例如,如果您想匹配正則.{3} <> [)}]&
表達式(3 個字元後跟 a" <> "
,a)
或}
a&
),您需要類似:[[ $var =~ .{3}" <> "[}\)]\& ]]
如果不確定哪些字元需要引用,您可以隨時使用臨時變數。這也意味著它將使程式碼與
bash31
,zsh
或兼容ksh93
:pattern='.{3} <> [})]&' [[ $var =~ $pattern ]] # remember *not* to quote $pattern here
這也是您可以使用系統正則表達式的非 POSIX 擴展運算符的唯一方法(不使用
compat31
選項(或))。BASH_COMPAT=3.1
例如,要
\<
在許多正則表達式引擎中被視為單詞邊界,您需要:pattern='\<word\>' [[ $var =~ $pattern ]]
正在做:
[[ $var =~ \<word\> ]]
不會
bash
將它們\
視為 shell 引用運算符並在傳遞<word>
給 regexp 庫之前將它們剝離。請注意,在 ksh93 中情況要糟糕得多,其中:
[[ $var =~ "x.*$" ]]
例如將匹配 on
whatever-xa*
但不匹配whatever-xfoo
。上面的引用刪除了 to 的特殊含義*
,但沒有刪除 to.
nor$
。
zsh
行為更簡單:引用不會改變那裡的正則表達式運算符的含義(如在 bash31 中),這使得行為更可預測(它也可以使用 PCRE 正則表達式而不是 ERE(帶有)set -o rematchpcre
)。
yash
沒有[[...]]
構造,但它的[
內置有一個=~
運算符(也在zsh
)。當然,[
作為普通命令,引用不會影響正則表達式運算符的解釋方式。另請注意,嚴格來說,您
$s
不包含 3 行,而是 2 個完整的行,後跟一個未終止的行。它包含hello\nworld\nOK
. 在OK$
擴展的正則表達式中,$
運算符只會匹配字元串的末尾。在 3-full-lines string中,例如
hello\nworld\nOK\n
(您將無法通過命令替換獲得它,因為命令替換會去除所有尾隨換行符), ,$
之後將匹配\n
,因此OK$
不會匹配它。
zsh -o pcrematch
但是,如果存在匹配項,則$
匹配字元串末尾和字元串末尾換行符之前的匹配項,因為它沒有將標誌PCRE_DOLLAR_ENDONLY
傳遞給pcre_compile
. 這可能被視為一個壞主意,因為 shell 中的變數通常不包含尾隨換行符,當它們包含時,我們通常希望它們被視為 data。