Je souhaite déterminer si une chaîne multiligne se termine par une ligne contenant le motif spécifié.
Ce code a échoué, il ne correspond pas.
s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match
Réponse acceptée :
Dans bash
3.2 ou supérieur et si la compatibilité à 3.1 n'est pas activée (avec le compat31
option ou BASH_COMPAT=3.1
), citant les opérateurs d'expression régulière (pas seulement avec mais avec n'importe lequel des
bash
opérateurs de guillemets ('...'
, "..."
, $'...'
, $"..."
)) supprime leur signification particulière.
[[ $var =~ 'OK$' ]]
correspond uniquement aux chaînes contenant OK$
littéralement (ce $
correspond à un $
littéral )
[[ $var =~ OK$ ]]
correspond aux chaînes qui se terminent par OK
(que $
est l'opérateur RE qui correspond à la fin de la chaîne).
Cela s'applique également aux expressions rationnelles stockées dans des variables ou le résultat d'une substitution.
[[ $var =~ $regexp ]] # $var matches $regexp
[[ $var =~ "$string" ]] # $var contains $string
Notez que cela peut devenir gênant car il y a certains caractères que vous devez citer pour la syntaxe du shell (comme les blancs, <
, >
, &
, parenthèse lorsqu'il n'y a pas de correspondance). Par exemple, si vous souhaitez faire correspondre le .{3} <> [)}]&
regexp (3 caractères suivis d'un " <> "
, soit un )
ou }
et un &
), vous avez besoin de quelque chose comme :
[[ $var =~ .{3}" <> "[})]& ]]
En cas de doute sur les caractères à citer, vous pouvez toujours utiliser une variable temporaire. Cela signifie également que cela rendra le code compatible avec bash31
, zsh
ou ksh93
:
pattern='.{3} <> [})]&'
[[ $var =~ $pattern ]] # remember *not* to quote $pattern here
C'est aussi le seul moyen (à moins d'utiliser le compat31
option (ou BASH_COMPAT=3.1
)), vous pouvez utiliser les opérateurs étendus non POSIX des expressions rationnelles de votre système.
Par exemple, pour <
pour être traité comme la limite de mot qu'il est dans de nombreux moteurs d'expressions régulières, vous avez besoin :
pattern='<word>'
[[ $var =~ $pattern ]]
En cours :
[[ $var =~ <word> ]]
ne fonctionnera pas comme bash
traite ces en tant qu'opérateurs de guillemets shell et supprimez-les avant de passer
<word>
à la bibliothèque regexp.
Notez que c'est bien pire dans ksh93 où :
[[ $var =~ "x.*$" ]]
par exemple correspondra sur whatever-xa*
mais pas whatever-xfoo
. La citation ci-dessus supprime la signification particulière de *
, mais pas à .
ni $
.
Le zsh
le comportement est plus simple :la citation ne change pas la signification des opérateurs d'expression régulière (comme dans bash31), ce qui rend le comportement plus prévisible (il peut également utiliser des expressions régulières PCRE au lieu d'ERE (avec set -o rematchpcre
)).
yash
n'a pas de [[...]]
construction, mais son [
intégré a un =~
opérateur (également en zsh
). Et bien sûr, [
étant une commande normale, les guillemets ne peuvent pas affecter la façon dont les opérateurs d'expression régulière sont interprétés.
Notez également qu'à proprement parler, vos $s
ne contient pas 3 lignes, mais 2 lignes pleines suivies d'une ligne non terminée. Il contient hellonworldnOK
. Dans le OK$
expression régulière étendue, le $
l'opérateur ne correspondrait qu'à la fin de la chaîne .
Dans une chaîne de 3 lignes complètes , comme hellonworldnOKn
(ce que vous ne pourriez pas obtenir avec la substitution de commande car la substitution de commande supprime tout caractères de fin de ligne), le $
correspondrait après le n
, donc OK$
ne correspondrait pas.
Avec zsh -o pcrematch
cependant, le $
correspond à la fois à la fin de la chaîne et avant la nouvelle ligne à la fin de la chaîne s'il y en a une car elle ne passe pas le PCRE_DOLLAR_ENDONLY
drapeau à pcre_compile
. Cela pourrait être considéré comme une mauvaise idée car généralement, les variables dans les shells ne contiennent pas de caractère de fin de ligne, et lorsqu'elles le font, nous voulons généralement qu'elles soient considérées comme des données.