Il semble que jutilise mal grep / egrep.

Jessayais de rechercher des chaînes sur plusieurs lignes et je nai pas trouvé de correspondance alors que je sais que ce que je recherche doit correspondre. Au départ, je pensais que mes expressions régulières étaient fausses mais jai finalement lu que celles-ci les outils fonctionnent par ligne (mes expressions régulières étaient aussi si triviales que cela ne pouvait pas être le problème).

Alors, quel outil utiliserait-on pour rechercher des modèles sur plusieurs lignes?

Commentaires

  • duplication possible de Correspondance de modèle multiligne avec sed, awk ou grep
  • @CiroSantilli – Je ne pense pas que ce Q et celui auquel vous avez lié sont des doublons. Lautre Q demande comment vous ‘ faire une correspondance de motifs multilignes (cest-à-dire quel outil dois / puis-je utiliser pour le faire) alors que celui-ci demande comment faire cela avec grep. Ils sont étroitement liés mais pas dups, IMO.
  • @sim ces cas sont difficile de décider: je peux voir votre point. Je pense que ce cas particulier est meilleur comme duplicata car que lutilisateur a dit "grep" suggérant le verbe  » à grep « , et les principales réponses, y compris accepté, nutilisez pas ‘ grep.
  • Il ny a aucune indication pour montrer quune expression régulière multiligne est nécessaire ici. Veuillez envisager de montrer un exemple réel avec les données dentrée et les données de sortie attendues, ainsi que votre effort précédent.

Réponse

Voici « sa sed celui qui vous donnera un comportement semblable à grep sur plusieurs lignes:

sed -n "/foo/{:start /bar/!{N;b start};/your_regex/p}" your_file 

Comment ça marche

  • -n supprime le comportement par défaut dimpression de chaque ligne
  • /foo/{} lui indique de correspondre à foo et faites ce qui se trouve à lintérieur des squigglies jusquaux lignes correspondantes. Remplacez foo par la partie de départ du motif.
  • :start est une étiquette de branchement pour nous aider à continuer à boucler jusquà ce que nous trouvions la fin de notre regex.
  • /bar/!{} exécutera ce qui est dans les squigglies à les lignes qui ne correspondent pas à bar. Remplacez avec la partie finale du motif.
  • N ajoute la ligne suivante au tampon actif (sed appelle cela lespace de motif)
  • b start se branchera inconditionnellement à létiquette start que nous avons créée plus tôt afin de continuer à ajouter la ligne suivante tant que lespace du motif ne contient pas bar.
  • /your_regex/p imprime lespace du motif sil correspond à your_regex. Vous devez remplacer your_regex par lexpression entière que vous souhaitez faire correspondre sur plusieurs lignes.

Commentaires

  • +1 Ajout de ceci à la toolikt! Merci.
  • Remarque: sur MacOS, cela génère une erreur sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
  • Obtention de sed: unterminated {
  • @Nomaed Tourné dans le noir ici, mais votre expression régulière contient-elle des caractères  » {« ? Si tel est le cas, vous ‘ devrez les échapper à la barre oblique inverse.
  • @Nomaed Il semble que cela ait à voir avec les différences entre les implémentations de sed. Jai essayé de suivre les recommandations de cette réponse pour rendre le script ci-dessus conforme à la norme, mais cela ma dit que  » start  » était un étiqueter. Donc, je ‘ ne sais pas si cela peut être fait dune manière conforme aux normes. Si vous le gérez, nhésitez pas à modifier ma réponse.

Réponse

Jutilise généralement un outil appelé pcregrep qui peut être installé dans la plupart des versions Linux en utilisant yum ou apt.

Par exemple.

Supposons que vous ayez un fichier nommé testfile avec un contenu

abc blah blah blah def blah blah blah 

Vous pouvez exécuter la commande suivante:

$ pcregrep -M "abc.*(\n|.)*def" testfile 

pour faire une correspondance de motifs sur plusieurs lignes.

De plus, vous pouvez faire la même chose avec sed.

$ sed -e "/abc/,/def/!d" testfile 

Commentaires

  • cette sed suggestion est ignorée la ligne où def se trouverait

Answer

Simplement un grep normal qui prend en charge le Perl-regexp paramètre P fera ce travail.

$ echo "abc blah blah blah def blah blah blah" | grep -oPz "(?s)abc.*?def" abc blah blah blah def 

(?s) appelé le modificateur DOTALL qui fait que le point dans votre expression régulière correspond non seulement aux caractères mais aussi aux sauts de ligne.

Commentaires

  • Quand jessaye cette solution, la sortie ne se termine pas à ‘ def ‘ mais va à la fin du fichier ‘ blah ‘
  • peut-être votre grep ne prend pas en charge loption -P
  • Cétait la seule qui fonctionnait pour moi – jai essayé toutes les sed suggestions, mais ‘ nest pas allé jusquà installer des alternatives grep.
  • $ grep --version: grep (GNU grep) 3.1 dans Windows Git Bash a une option -P, --perl-regexp mais (?s) ne ‘ t semble fonctionner là-bas. Il affiche toujours la première ligne uniquement. Le même modèle avec la même chaîne de test fonctionne sur regex101.com . Y a-t-il une alternative dans le Git Bash? sed? (sed (GNU sed) 4.8 ici)
  • Savez-vous comment ajouter un contexte à la sortie? grep -1 ne fonctionne ‘ ici.

Réponse

Voici « une approche plus simple utilisant Perl:

perl -e "$f=join("",<>); print $& if $f=~/foo\nbar.*\n/m" file 

ou (puisque JosephR a pris le sed itinéraire , je « volerai sans vergogne sa suggestion )

perl -n000e "print $& while /^foo.*\nbar.*\n/mg" file 

### Explication

$f=join("",<>);: ceci lit le fichier entier et enregistre son contenu (retours à la ligne et tout) dans la variable $f. Nous essayons ensuite de faire correspondre foo\nbar.*\n, et de limprimer si cela correspond (la variable spéciale $& contient la dernière correspondance trouvée). ///m est nécessaire pour faire correspondre lexpression régulière entre les sauts de ligne.

-0 définit le séparateur denregistrement dentrée. Le paramétrer sur 00 active le « mode paragraphe » où Perl utilisera des retours à la ligne consécutifs (\n\n) comme séparateur denregistrement. Dans les cas où il ny a pas de sauts de ligne consécutifs, le fichier entier est lu (slurped) à la fois.

### Attention: Ne faites pas cela pour les gros fichiers, il se chargera le fichier entier en mémoire et cela peut être un problème.

Commentaires

  • I don ‘ t en savoir beaucoup sur Perl, mais ne ‘ t-il pas besoin dêtre my $f=join("",<>); à proprement parler?
  • @Sapphire_Brick uniquement si vous êtes en mode strict (use strict;). C’est ‘ une bonne habitude à prendre, en particulier lors de l’écriture de scripts plus volumineux, mais ‘ est un problème pour un petit one-liner comme celui-ci un.

Réponse

Supposons que nous ayons le fichier test.txt contenant:

blabla blabla foo here is the text to keep between the 2 patterns bar blabla blabla 

Le code suivant peut être utilisé:

sed -n "/foo/,/bar/p" test.txt 

Pour la sortie suivante:

foo here is the text to keep between the 2 patterns bar 

Réponse

Lalternative grep sift prend en charge la correspondance multiligne (avertissement: je suis lauteur).

Supposons que testfile contient:

 <book> <title>Lorem Ipsum</title> <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</description> </book> 

sift -m '<description>.*?</description>' (affiche les lignes contenant la description)

Résultat:

 testfile: <description>Lorem ipsum dolor sit amet, consectetur testfile: adipiscing elit, sed do eiusmod tempor incididunt ut testfile: labore et dolore magna aliqua</description> 

sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename (extraire et reformater la description)

Résultat:

description="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua" 

Commentaires

  • Très bel outil. Toutes nos félicitations! Essayez de linclure dans des distributions comme Ubuntu.

Réponse

Jai résolu celui-ci pour moi en utilisant grep et – Une option avec un autre grep.

grep first_line_word -A 1 testfile | grep second_line_word 

Loption -A 1 imprime 1 ligne après la ligne trouvée. Bien sûr, cela dépend de votre combinaison de fichiers et de mots. Mais pour moi, cétait la solution la plus rapide et la plus fiable.

Commentaires

  • alias grepp = ‘ grep –color = auto -B10 -A20 -i ‘ puis cat somefile | grepp blah | grepp foo | grepp bar … oui ceux -A et -B sont très pratiques …vous avez la meilleure réponse
  • Ceci nest pas ‘ t super déterministe et il ignore tout le modèle en faveur de lobtention dune seule ligne différente (juste en fonction de sa proximité à la première ligne). Il est ‘ de dire au programme d’aller aussi loin que nécessaire pour arriver à une sorte de modèle que vous ‘ re absolument certain que la fin du texte que vous ‘ essayez de faire correspondre. Par exemple, si testfile est mis à jour de telle sorte que second_line_word se trouve sur la troisième ligne, non seulement vous manquez maintenant la première ligne (en raison de votre deuxième grep) mais vous ‘ ne manquez pas la ligne qui a commencé à apparaître entre les deux.
  • Ceci serait un MO assez bon pour les commandes ad hoc où vous ne voulez vraiment quune seule ligne en sortie que vous avez déjà comprise. Je ne ‘ ne pense pas que ‘ est ce que lOP est après et vous pourriez probablement aussi simplement copier / coller à ce stade en raison de cela étant ad hoc.

Réponse

Une façon de faire est dutiliser Perl. par exemple. voici le contenu dun fichier nommé foo:

foo line 1 bar line 2 foo foo foo line 5 foo bar line 6 

Maintenant, voici un peu de Perl qui va correspond à toute ligne commençant par foo suivie de toute ligne commençant par bar:

cat foo | perl -e "while(<>){$all .= $_} while($all =~ /^(foo[^\n]*\nbar[^\n]*\n)/m) { print $1; $all =~ s/^(foo[^\n]*\nbar[^\n]*\n)//m; }" 

Le Perl, décomposé:

  • while(<>){$all .= $_} Ceci charge toute lentrée standard dans la variable $all
  • while($all =~ Alors que la variable all a lexpression régulière …
  • /^(foo[^\n]*\nbar[^\n]*\n)/m Le regex: foo au début de la ligne, suivi par un nombre quelconque de caractères non-nouvelle ligne, suivi dun saut de ligne, suivi immédiatement par « bar », et le reste de la ligne avec bar. /m à la fin de lexpression régulière signifie « correspondance sur plusieurs lignes »
  • print $1 Imprimer la partie de lexpression régulière qui était entre parenthèses (dans ce cas, lexpression régulière entière)
  • s/^(foo[^\n]*\nbar[^\n]*\n)//m Effacez la première correspondance pour lexpression régulière, afin que nous puissions faire correspondre plusieurs cas de lexpression régulière dans le fichier en question

Et la sortie:

foo line 1 bar line 2 foo bar line 6 

Commentaires

  • Je viens de dire que votre Perl peut être raccourci au plus idiomatique: perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo

Réponse

Si nous voulons obtenir le texte entre les 2 motifs en excluant eux-mêmes.

Supposons que nous ayons le fichier test.txt contenant:

blabla blabla foo here is the text to keep between the 2 patterns bar blabla blabla 

Le code suivant peut être utilisé:

 sed -n "/foo/{ n b gotoloop :loop N :gotoloop /bar/!{ h b loop } /bar/{ g p } }" test.txt 

Pour la sortie suivante:

here is the text to keep between the 2 patterns 

Comment ça marche, laissez « s faites-le étape par étape

  1. /foo/{ est déclenché lorsque la ligne contient « foo »
  2. n remplacez lespace du motif par la ligne suivante, cest-à-dire le mot « here »
  3. b gotoloop branche sur létiquette « gotoloop »
  4. :gotoloop définit le libellé « gotoloop »
  5. /bar/!{ si le motif ne contient pas « bar »
  6. h remplacer lespace de maintien par un motif, donc « here » est enregistré dans lespace de maintien
  7. b loop branche au libellé « loop »
  8. :loop définit le libellé « loop »
  9. N ajoute le modèle à lespace de conservation.
    Lespace de conservation contient maintenant:
    « ici »
    « est le »
  10. :gotoloop Nous sommes maintenant à létape 4, et boucle jusquà ce quune ligne contienne « bar »
  11. /bar/ la boucle est terminée, « bar » a été trouvé, il  » s lespace du motif
  12. lespace de motif est remplacé par un espace de maintien qui contient toutes les lignes entre » foo « et » bar « qui ont été sauvegardées pendant la boucle principale
  13. p copie lespace de motif sur la sortie standard

Terminé!

Commentaires

  • Bravo, +1. Jévite généralement dutiliser ces commandes en tr ‘ les nouvelles lignes dans SOH et en exécutant des commandes sed normales puis en remplaçant les nouvelles lignes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *