GNU/Linux >> Tutoriels Linux >  >> Linux

Shell teste si la chaîne de plusieurs lignes contient le modèle spécifié dans la dernière ligne ?

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 )).

Connexe :option de menu contextuel Nautilus pour créer un nouveau fichier ?

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.


Linux
  1. Comment supprimer les premières/dernières lignes 'n' de la sortie de la commande dans Shell ?

  2. Cat ligne X à ligne Y sur un énorme fichier ?

  3. Dans un shell Linux, comment puis-je traiter chaque ligne d'une chaîne multiligne ?

  4. Comment remplacer une chaîne dans plusieurs fichiers en ligne de commande Linux

  5. Insérer plusieurs lignes dans un fichier après le motif spécifié à l'aide d'un script shell

Comment commenter plusieurs lignes à la fois dans l'éditeur Vim

Comment savoir si une durée est supérieure à une heure sur plusieurs scripts shell ?

Comment ajouter plusieurs lignes à un fichier ?

Supprimer la ligne contenant une certaine chaîne et la ligne suivante ?

Comment supprimer plusieurs lignes dans Vim

Comment modifier les lignes précédentes dans une commande à plusieurs lignes dans Bash ?