Il semble que j'abuse grep
/ egrep
.
J'essayais de rechercher des chaînes sur plusieurs lignes et je n'ai pas trouvé de correspondance alors que je sais que ce que je recherche doit correspondre. À l'origine, je pensais que mes expressions rationnelles étaient erronées, mais j'ai finalement lu que ces outils fonctionnent par ligne (également mes expressions régulières étaient si triviales que cela ne pouvait pas être le problème).
Alors, quel outil utiliserait-on pour rechercher des modèles sur plusieurs lignes?
grep
. Ils sont étroitement liés mais pas dupes, OMI."grep"
suggérer le verbe "à grep", et les meilleures réponses, y compris acceptées, n'utilisent pas grep.Réponses:
En voici
sed
un qui vous donnera ungrep
comportement semblable à plusieurs lignes:Comment ça marche
-n
supprime le comportement par défaut de l'impression de chaque ligne/foo/{}
lui demande de faire correspondrefoo
et de faire ce qui vient à l'intérieur des gribouillis aux lignes correspondantes. Remplacezfoo
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 expression régulière./bar/!{}
exécutera ce qui est dans les gribouillis sur les lignes qui ne correspondent pasbar
. Remplacezbar
par la partie finale du motif.N
ajoute la ligne suivante au tampon actif (sed
appelle cela l'espace de motif)b start
se ramifiera inconditionnellement à l'start
étiquette que nous avons créée plus tôt afin de continuer à ajouter la ligne suivante tant que l'espace de motif ne contient pasbar
./your_regex/p
imprime l'espace de motif s'il correspondyour_regex
. Vous devez remplaceryour_regex
par l'expression entière que vous souhaitez faire correspondre sur plusieurs lignes.la source
sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
sed: unterminated {
erreursed
implémentations. J'ai essayé de suivre les recommandations de cette réponse pour rendre le script ci-dessus conforme aux normes, mais il m'a dit que "démarrer" était une étiquette non définie. Je ne sais donc pas si cela peut être fait de manière conforme aux normes. Si vous y parvenez, n'hésitez pas à modifier ma réponse.J'utilise généralement un outil appelé
pcregrep
qui peut être installé dans la plupart des versions linux en utilisantyum
ouapt
.Par exemple.
Supposons que vous ayez un fichier nommé
testfile
avec du contenuVous pouvez exécuter la commande suivante:
pour faire correspondre les modèles sur plusieurs lignes.
De plus, vous pouvez également faire de même avec
sed
.la source
Voici une approche plus simple en utilisant Perl:
ou (puisque JosephR a pris la
sed
route , je vais voler sans vergogne sa suggestion )Explication
$f=join("",<>);
: ceci lit le fichier entier et enregistre son contenu (sauts de ligne et tout) dans la variable$f
. Nous essayons ensuite de faire correspondrefoo\nbar.*\n
et de l'imprimer s'il correspond (la variable spéciale$&
contient la dernière correspondance trouvée). Le///m
est nécessaire pour faire correspondre l'expression régulière entre les nouvelles lignes.Le
-0
définit le séparateur d'enregistrement d'entrée. La définition de ce paramètre00
active le «mode paragraphe» où Perl utilisera des sauts de ligne consécutifs (\n\n
) comme séparateur d'enregistrement. Dans les cas où il n'y a pas de sauts de ligne consécutifs, le fichier entier est lu (slurped) à la fois.Attention:
Ne faites pas cela pour les fichiers volumineux, cela chargera le fichier entier en mémoire et cela peut être un problème.
la source
Une façon de le faire est avec Perl. par exemple, voici le contenu d'un fichier nommé
foo
:Maintenant, voici quelques Perl qui correspondront à n'importe quelle ligne commençant par foo suivie par toute ligne commençant par bar:
Le Perl, décomposé:
while(<>){$all .= $_}
Cela charge l'intégralité de l'entrée standard dans la variable$all
while($all =~
Alors que la variableall
a l'expression régulière .../^(foo[^\n]*\nbar[^\n]*\n)/m
L'expression régulière: foo au début de la ligne, suivie d'un nombre quelconque de caractères non-newline, suivie d'une nouvelle ligne, suivie immédiatement de "bar" et du reste de la ligne avec barre./m
à la fin de l'expression régulière signifie "correspondance sur plusieurs lignes"print $1
Imprimer la partie de l'expression régulière qui était entre parenthèses (dans ce cas, l'expression régulière entière)s/^(foo[^\n]*\nbar[^\n]*\n)//m
Effacer la première correspondance pour l'expression régulière, afin que nous puissions faire correspondre plusieurs cas de l'expression régulière dans le fichier en questionEt la sortie:
la source
perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo
La solution grep EIPD soutient correspondant multiligne (disclaimer: je suis l'auteur).
Supposons que
testfile
contient:sift -m '<description>.*?</description>'
(montrer les lignes contenant la description)Résultat:
sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename
(extraire et reformater la description)Résultat:
la source
Un simple grep normal qui prend en charge le
Perl-regexp
paramètreP
fera ce travail.(?s)
appelé modificateur DOTALL qui fait que les points de votre expression régulière correspondent non seulement aux caractères mais aussi aux sauts de ligne.la source
-P
optionJ'ai résolu celui-ci pour moi en utilisant grep et l'option -A avec un autre grep.
L'option -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.
la source
Supposons que nous ayons le fichier test.txt contenant:
Le code suivant peut être utilisé:
Pour la sortie suivante:
la source
Si nous voulons obtenir le texte entre les 2 motifs en s'excluant.
Supposons que nous ayons le fichier test.txt contenant:
Le code suivant peut être utilisé:
Pour la sortie suivante:
Comment ça marche, faisons-le pas à pas
/foo/{
est déclenché lorsque la ligne contient "foo"n
remplacer l'espace de motif par la ligne suivante, c'est-à-dire le mot "ici"b gotoloop
branchement au label "gotoloop":gotoloop
définit le label "gotoloop"/bar/!{
si le motif ne contient pas "bar"h
remplacer l'espace de maintien par un motif, donc "ici" est enregistré dans l'espace de maintienb loop
branche au label "boucle":loop
définit l'étiquette "boucle"N
ajoute le motif à l'espace d'attente.Maintenant, l'espace de stockage contient:
"ici"
"est le"
:gotoloop
Nous sommes maintenant à l'étape 4, et bouclons jusqu'à ce qu'une ligne contienne "bar"/bar/
la boucle est terminée, "bar" a été trouvé, c'est l'espace du motifg
l'espace de motif est remplacé par un espace d'attente qui contient toutes les lignes entre "foo" et "bar" qui ont été enregistrées pendant la boucle principalep
copier l'espace du motif sur la sortie standardTerminé !
boucle multiligne sed
la source