Duplicate possible:
Comment puis-je rechercher un motif multiligne dans un fichier? Utilisez pcregrep
J'utilise un grep
pour rechercher un fichier * .sql contenant 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 nouvelles lignes.
J'ai essayé quelques variations sur les points suivants:
$ grep -liIr --include="*.sql" --exclude-dir="\.svn*" --regexp="select[a-zA-Z0-
9+\n\r]*customerName[a-zA-Z0-9+\n\r]*from"
Ceci, cependant, fonctionne juste pour toujours. Quelqu'un peut-il m'aider avec la syntaxe correcte s'il vous plaît?
Sans la nécessité d'installer la variante pcprep de grep, vous pouvez effectuer une recherche multiligne avec grep.
$ grep -Pzo "(?s)^(\s*)\N*main.*?{.*?^\1}" *.c
Explication:
-P
activer Perl-regexp pour grep (une extension puissante des expressions régulières)
-z
supprime la nouvelle ligne à la fin de la ligne, la sous-titrant pour un caractère nul. C'est-à-dire que grep sait où se trouve la fin de la ligne, mais voit l'entrée comme une grosse ligne.
-o
imprime uniquement les correspondances. Parce que nous utilisons -z
, le fichier entier est comme une seule grande ligne, ainsi s'il y a correspondance, le fichier entier sera imprimé; De cette façon, il ne le fera pas.
En regexp:
(?s)
active PCRE_DOTALL
, ce qui signifie que .
trouve un caractère ou une nouvelle ligne.
\N
ne trouve rien sauf la nouvelle ligne, même avec PCRE_DOTALL
activé
.*?
trouve .
en mode non planifié, c'est-à-dire qu'il s'arrête le plus tôt possible.
^
recherche le début de la ligne
\1
backreference au premier groupe (\s*
) Ceci est une tentative pour trouver la même indentation de méthode
Comme vous pouvez l'imaginer, cette recherche imprime la méthode principale dans un fichier source C (*.c
).
Je ne suis pas très bon en Grèce. Mais votre problème peut être résolu en utilisant la commande AWK . Tu verras
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 instructions retournées ont customername
ou non. Pour cela, vous pouvez diriger le résultat. Et peut utiliser awk ou grep à nouveau.
Votre problème fondamental est que grep
fonctionne une ligne à la fois - il ne peut donc pas trouver une instruction SELECT répartie sur plusieurs lignes.
Votre deuxième problème est que les expressions rationnelles que vous utilisez ne traitent pas de la complexité de ce qui peut apparaître entre SELECT et FROM - en particulier, elle omet les virgules, les points, les espaces, mais aussi les guillemets une chaîne entre guillemets.
Je préférerais utiliser une solution basée sur Perl, Perl lisant des "paragraphes" à la fois et appliquant une expression régulière à cela. L'inconvénient est d'avoir à faire avec la recherche récursive - il existe des modules pour le faire, bien sûr, y compris le module de base File :: Find .
En résumé, pour un seul fichier:
$/ = "\n\n"; # Paragraphs
while (<>)
{
if ($_ =~ m/SELECT.*customerName.*FROM/mi)
{
printf file name
go to next file
}
}
Cela doit être encapsulé dans un sous-répertoire qui est ensuite appelé par les méthodes File :: Find.