Regex (grep) pour la recherche multi-ligne nécessaire [dupliquer]
possibilité de duplication:
Comment puis-je rechercher un motif multiligne dans un fichier ? Utilisation pcregrep
je suis à court d'un grep
pour trouver tout *.fichier sql qui a le mot select
, suivi du mot customerName
, suivi du mot from
. Cette instruction select peut couvrir plusieurs lignes et peut contenir des onglets et des lignes.
j'ai essayé quelques variantes sur le suivant:
$ grep -liIr --include="*.sql" --exclude-dir=".svn*" --regexp="select[a-zA-Z0-
9+nr]*customerName[a-zA-Z0-9+nr]*from"
cela, cependant, court pour toujours. Quelqu'un peut m'aider avec la syntaxe correcte s'il vous plaît?
3 réponses
sans la nécessité d'installer la variante grep pcregrep, vous pouvez faire la recherche multiligne avec grep.
$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^}" *.c
explication:
-P
activer perl-regexp pour grep (une puissante extension de régulièrement des extensions)
-z
supprimer newline à la fin de la ligne, en la remplaçant par le caractère nul. C'est, grep sait où la fin de la ligne, mais voit l'entrée comme une grande ligne.
-o
imprimer uniquement de la correspondance. Parce que nous utilisons -z
, le fichier entier est comme une seule grande ligne, donc s'il y a une correspondance, le fichier entier serait imprimé; de cette façon il ne fera pas cela.
Dans regexp:
(?s)
activer PCRE_DOTALL
, ce qui signifie que .
trouve n'importe quel caractère ou nouvelle ligne
\N
trouver autre chose que newline, même avec PCRE_DOTALL
activé
.*?
trouver .
dans nongreedy mode, qui est, s'arrête dès que possible.
"1519120920 trouver" début de ligne
la référence arrière à premier groupe (
\s*
) C'est d'essayer de trouver de même indentation de la méthode
comme vous pouvez l'imaginer, cette recherche affiche la méthode principale dans un fichier source C ( *.c
).
Je ne suis pas très bon en grep. Mais votre problème peut être résolu en utilisant la commande AWK . Voir
awk '/select/,/from/' *.sql
le code ci-dessus résultera de la première occurrence de select
jusqu'à la première séquence de from
. Maintenant, vous devez vérifier si les déclarations retournées ont customername
ou non. Pour cela, vous pouvez rediriger le résultat. Et peut utiliser awk ou grep à nouveau.
votre problème fondamental est que grep
fonctionne une ligne à la fois - de sorte qu'il ne peut pas trouver une déclaration SELECT étalé sur les lignes.
votre deuxième problème est que le regex que vous utilisez ne traite pas de la complexité de ce qui peut apparaître entre SELECT et FROM - en particulier, il omet les virgules, les arrêts complets (périodes) et les blancs, mais aussi les guillemets et tout ce qui peut être à l'intérieur d'une chaîne Citée.
j'irais probablement avec un Perl-basé solution Perl lire "paragraphes" à un moment et en appliquant une regex. L'inconvénient est d'avoir à gérer la recherche récursive - il y a des modules pour le faire, bien sûr, y compris le module de base fichier::Find .
dans les grandes lignes, pour un seul fichier:
$/ = "\n\n"; # Paragraphs
while (<>)
{
if ($_ =~ m/SELECT.*customerName.*FROM/mi)
{
printf file name
go to next file
}
}
qui doit être enveloppé dans un sub qui est alors invoqué par les méthodes de File::Find.