Quiero determinar si una cadena de varias líneas termina con una línea que contiene un patrón específico.
Este código falló, no coincide.
s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match
Respuesta aceptada:
En bash
3.2 o superior y si la compatibilidad con 3.1 no está habilitada (con el compat31
opción o BASH_COMPAT=3.1
), citando operadores de expresiones regulares (no solo con pero con cualquiera de los
bash
operadores de comillas ('...'
, "..."
, $'...'
, $"..."
)) elimina su significado especial.
[[ $var =~ 'OK$' ]]
coincide solo en cadenas que contienen OK$
literalmente (que $
coincide con un literal $
)
[[ $var =~ OK$ ]]
coincidencias en cadenas que terminan en OK
(que $
es el operador RE que coincide al final de la cadena).
Eso también se aplica a las expresiones regulares almacenadas en variables o el resultado de alguna sustitución.
[[ $var =~ $regexp ]] # $var matches $regexp
[[ $var =~ "$string" ]] # $var contains $string
Tenga en cuenta que puede volverse incómodo porque hay algunos caracteres que debe citar para la sintaxis de shell (como espacios en blanco, <
, >
, &
, paréntesis cuando no coincide). Por ejemplo, si desea hacer coincidir con el .{3} <> [)}]&
expresión regular (3 caracteres seguidos de un " <> "
, ya sea un )
o }
y un &
), necesitas algo como:
[[ $var =~ .{3}" <> "[})]& ]]
Si tiene dudas sobre qué caracteres necesitan citarse, siempre puede usar una variable temporal. Eso también significa que hará que el código sea compatible con bash31
, zsh
o ksh93
:
pattern='.{3} <> [})]&'
[[ $var =~ $pattern ]] # remember *not* to quote $pattern here
Esa es también la única forma (aparte de usar el compat31
opción (o BASH_COMPAT=3.1
)) puede hacer uso de los operadores extendidos no POSIX de las expresiones regulares de su sistema.
Por ejemplo, para <
para ser tratado como el límite de palabras que es en muchos motores de expresiones regulares, necesita:
pattern='<word>'
[[ $var =~ $pattern ]]
Haciendo:
[[ $var =~ <word> ]]
no funcionará como bash
trata a esos como operadores de comillas de shell y eliminarlos antes de pasar
<word>
a la biblioteca de expresiones regulares.
Tenga en cuenta que es mucho peor en ksh93 donde:
[[ $var =~ "x.*$" ]]
por ejemplo, coincidirá con whatever-xa*
pero no whatever-xfoo
. La cita anterior elimina el significado especial de *
, pero no a .
ni $
.
El zsh
el comportamiento es más simple:citar no cambia el significado de los operadores de expresiones regulares allí (como en bash31), lo que hace que el comportamiento sea más predecible (también puede usar expresiones regulares de PCRE en lugar de ERE (con set -o rematchpcre
)).
yash
no tiene un [[...]]
construir, pero es [
incorporado tiene un =~
operador (también en zsh
). Y por supuesto, [
siendo un comando normal, las comillas no pueden afectar la forma en que se interpretan los operadores de expresiones regulares.
También tenga en cuenta que estrictamente hablando, su $s
no contiene 3 líneas, sino 2 líneas completas seguidas de una línea sin terminar. Contiene hellonworldnOK
. En el OK$
expresión regular extendida, el $
el operador solo coincidiría al final de la cadena .
En una cadena de 3 líneas completas , como hellonworldnOKn
(que no podría obtener con la sustitución de comandos, ya que la sustitución de comandos elimina todo caracteres finales de nueva línea), el $
coincidiría después de n
, entonces OK$
no coincidiría con él.
Con zsh -o pcrematch
sin embargo, el $
coincide tanto al final de la cadena como antes de la nueva línea al final de la cadena si hay una, ya que no pasa el PCRE_DOLLAR_ENDONLY
marcar a pcre_compile
. Eso podría verse como una mala idea ya que, por lo general, las variables en los shells no contienen un carácter de nueva línea final y, cuando lo hacen, generalmente queremos que se consideren como datos.