Voglio determinare se una stringa di più righe termina con una riga contenente un modello specificato.
Questi codici non sono riusciti, non corrisponde.
s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match
Risposta accettata:
In bash
3.2 o superiori e se la compatibilità con 3.1 non è abilitata (con il compat31
opzione o BASH_COMPAT=3.1
), citando gli operatori di espressioni regolari (non solo con ma con uno qualsiasi dei
bash
operatori di virgolette ('...'
, "..."
, $'...'
, $"..."
)) rimuove il loro significato speciale.
[[ $var =~ 'OK$' ]]
corrisponde solo nelle stringhe che contengono OK$
letteralmente (che $
corrisponde a un letterale $
)
[[ $var =~ OK$ ]]
corrisponde a stringhe che terminano con OK
(quel $
è l'operatore RE che corrisponde alla fine della stringa).
Ciò vale anche per le espressioni regolari memorizzate nelle variabili o il risultato di qualche sostituzione.
[[ $var =~ $regexp ]] # $var matches $regexp
[[ $var =~ "$string" ]] # $var contains $string
Nota che può diventare imbarazzante perché ci sono alcuni caratteri che devi citare per la sintassi della shell (come spazi vuoti, <
, >
, &
, parentesi quando non corrispondenti). Ad esempio, se vuoi confrontare .{3} <> [)}]&
regexp (3 caratteri seguiti da un " <> "
, un )
o }
e un &
), hai bisogno di qualcosa come:
[[ $var =~ .{3}" <> "[})]& ]]
In caso di dubbio su quali caratteri devono essere citati, puoi sempre utilizzare una variabile temporanea. Ciò significa anche che renderà il codice compatibile con bash31
, zsh
o ksh93
:
pattern='.{3} <> [})]&'
[[ $var =~ $pattern ]] # remember *not* to quote $pattern here
Questo è anche l'unico modo (a meno di usare il compat31
opzione (o BASH_COMPAT=3.1
)) puoi utilizzare gli operatori estesi non POSIX delle espressioni regolari del tuo sistema.
Ad esempio, per <
per essere trattato come il limite di parole che è in molti motori di espressioni regolari, è necessario:
pattern='<word>'
[[ $var =~ $pattern ]]
Fare:
[[ $var =~ <word> ]]
non funzionerà come bash
tratta quelli come operatori di citazione della shell e rimuoverli prima di passare
<word>
alla libreria regexp.
Nota che è molto peggio in ksh93 dove:
[[ $var =~ "x.*$" ]]
ad esempio corrisponderà su whatever-xa*
ma non whatever-xfoo
. La citazione sopra rimuove il significato speciale di *
, ma non a .
né $
.
Il zsh
il comportamento è più semplice:la citazione non cambia il significato degli operatori regexp lì (come in bash31), il che rende il comportamento più prevedibile (può anche usare le espressioni regolari PCRE invece di ERE (con set -o rematchpcre
)).
yash
non ha un [[...]]
costrutto, ma è [
builtin ha un =~
operatore (anche in zsh
). E, naturalmente, [
essendo un comando normale, le virgolette non possono influenzare il modo in cui vengono interpretati gli operatori regexp.
Nota anche che, a rigor di termini, il tuo $s
non contiene 3 righe, ma 2 righe complete seguite da una riga non terminata. Contiene hellonworldnOK
. Nel OK$
espressione regolare estesa, il $
l'operatore corrisponderebbe solo alla fine della stringa .
In una stringa di 3 righe intere , come hellonworldnOKn
(che non saresti in grado di ottenere con la sostituzione dei comandi poiché la sostituzione dei comandi rimuove tutti caratteri di nuova riga finali), il $
corrisponderebbe dopo il n
, quindi OK$
non corrisponderebbe.
Con zsh -o pcrematch
tuttavia, il $
corrisponde sia alla fine della stringa che prima della nuova riga alla fine della stringa se ce n'è una in quanto non supera il PCRE_DOLLAR_ENDONLY
segnala a pcre_compile
. Potrebbe essere vista come una cattiva idea poiché generalmente le variabili nelle shell non contengono un carattere di nuova riga finale e, quando lo fanno, generalmente le vogliamo considerate come dati.