2009-12-17 9 views
45

J'ai besoin d'un moyen de rechercher un fichier en utilisant grep via une expression régulière de la ligne de commande Unix. Par exemple, lorsque je tape dans la ligne de commande:Grep et Python

python pythonfile.py 'RE' 'file-to-be-searched' 

J'ai besoin l'expression régulière 'RE' à rechercher dans le fichier et imprimer les lignes correspondantes.

Voici le code que j'ai:

import re 
import sys 

search_term = sys.argv[1] 
f = sys.argv[2] 

for line in open(f, 'r'): 
    if re.search(search_term, line): 
     print line, 
     if line == None: 
      print 'no matches found' 

Mais quand je rentre un mot qui n'est pas présent, no matches found n'imprime pas

+0

Si vous voulez vraiment des expressions régulières de style python dans grep, l'option --perl-regex p est vraiment proche. Il vous donne un support d'expression régulière de type perl. (De plus, mon option sous-utilisée préférée pour grep est --color = always) –

Répondre

3
  1. utilisation sys.argv pour obtenir les paramètres de ligne de commande
  2. utiliser open(), read() pour manipuler le fichier
  3. utiliser le Python re module à mat ch lignes
59

La question naturelle est pourquoi ne pas simplement utiliser grep ?! Mais en supposant que vous ne pouvez pas ...

import re 
import sys 

file = open(sys.argv[2], "r") 

for line in file: 
    if re.search(sys.argv[1], line): 
     print line, 

choses à noter:

  • search au lieu de match trouver nulle part dans la chaîne
  • virgule (,) après print supprime le retour chariot (ligne sera avoir un)
  • argv inclut le nom de fichier python, donc les variables doivent commencer à 1

Cela ne gère pas les arguments multiples (comme le fait grep) ou développer les caractères génériques (comme le ferait le shell Unix). Si vous vouliez cette fonctionnalité, vous pouvez l'obtenir en utilisant les éléments suivants:

import re 
import sys 
import glob 

for arg in sys.argv[2:]: 
    for file in glob.iglob(arg): 
     for line in open(file, 'r'): 
      if re.search(sys.argv[1], line): 
       print line, 
+5

vous devriez compiler votre regex avant d'utiliser les boucles. – ghostdog74

+3

Cela a deux voix vers le bas et je ne sais pas pourquoi. Quelqu'un qui downvoted veut laisser un commentaire? Je sais que vous pourriez ajouter une compilation regex etc, mais je pensais que cela nuirait à la clarté de la réponse. Je ne pense pas qu'il y ait quelque chose d'incorrect, et j'ai exécuté le code, contrairement à d'autres réponses –

+0

Cette réponse était parfaite pour moi merci. Juste une autre question rapide comment pourrais-je imprimer si aucun match n'a été trouvé? – David

5

Adaptée d'un grep in python.

accepte une liste de noms de fichiers via [2:], ne fait pas la gestion des exceptions:

#!/usr/bin/env python 
import re, sys, os 

for f in filter(os.path.isfile, sys.argv[2:]): 
    for line in open(f).readlines(): 
     if re.match(sys.argv[1], line): 
      print line 

sys.argv[1] resp sys.argv[2:] œuvres, si vous l'exécutez comme un exécutable autonome, ce qui signifie

chmod +x

premier

+0

Quelle est la différence entre 're.match' et' re.search'? – OscarRyz

+2

@OscarRyz voir [meilleure réponse de Nick Fortescue] (http://stackoverflow.com/a/1921932/327074): "' search' au lieu de 'match' pour trouver n'importe où dans la chaîne" – icc97

2

Vous pourriez être intéressé par pyp Citant mon autre answer:

« Le Pyed Piper », ou pyp, est un outil de manipulation de texte en ligne de commande linux similaire à awk ou sed, mais qui utilise la chaîne de python standard et méthodes de la liste ainsi que des fonctions personnalisées évolué pour générer des résultats rapides dans un environnement de production intense.

7

Concise et efficace de la mémoire:

#!/usr/bin/env python 
# file: grep.py 
import re, sys 

map(sys.stdout.write,(l for l in sys.stdin if re.search(sys.argv[1],l))) 

Il fonctionne comme egrep (sans trop de gestion des erreurs), par exemple:

cat file-to-be-searched | grep.py "RE" 

Et voici le one-liner:

cat file-to-be-searched | python -c "import re,sys;map(sys.stdout.write,(l for l in sys.stdin if re.search(sys.argv[1],l)))" "RE" 
+1

Cela pourrait être refait avec un générateur et n'aurait pratiquement pas de mémoire. – vy32

+0

Merci d'avoir signalé cela. J'ai mis à jour la réponse en utilisant seulement des itérateurs. –

+0

C'est génial. Très bien fait. – vy32