Comment rechercher du texte dans un fichier en ignorant les sauts de ligne?


11

Je voudrais rechercher du texte qui peut être divisé en plusieurs lignes dans un fichier. Un grep qui ignorerait les sauts de ligne et retournerait la plage de lignes correspondante.

par exemple, je rechercherais is an example fileet je m'attends à ce qu'il se trouve dans le fichier suivant:

Ceci est
un
exemple de fichier.

Pour ne pas dépendre d'espaces de début ou de fin, ignorer entièrement toutes les formes d'espace blanc peut être préférable (idéalement, traiter toute séquence d'espace blanc comme un seul espace).


Une solution non idéale consiste à faire la tr '\n' ' ' | grepdistinction entre les correspondances et les non-correspondances, mais n'affiche pas la correspondance et ne traite pas bien les gros fichiers.


sur SO (pas de réponse définitive): stackoverflow.com/q/1858312/1449460
Nikana Reklawyks

En remarque, la recherche d'emacs semble faire l'affaire ( isearch-forward)
Nikana Reklawyks

Il en va de Vim: /This\_sis. Pour plus de détails: :help \_s.
lcd047

Ajoutez cette ligne à la fin de votre ligne de recherche: tr -n "\ n" Cela supprimera toutes les nouvelles lignes. J'espère que cette aide!
Dan Howel

Réponses:


12

Le GNU greppeut le faire

grep -z 'is\san\sexample\sfile.' file

Pour répondre à certains points soulevés dans les commentaires, il y a quelques modifications au script:

 grep -oz '^[^\n]*\bis\s*an\s*example\s*file\.[^\n]*' file

En ce qui concerne les fichiers volumineux, je n'ai aucune imagination de limitation de mémoire, mais en cas de problème, vous êtes libre d'utiliser sed

sed '/\bis\b/{
          :1
          N
          /file\.\|\(\n.*\)\{3\}/!b1
         }
     /\<is\s*an\s*example\s*file\./p
     D' file

qui ne gardent pas plus de 4 lignes (car 4 mots dans le motif) en mémoire ( \(\n.*\)\{3\}).


5
Comme je suis sûr que vous le savez, l' -zoption indique grepde traiter les retours à la ligne comme des caractères de texte ordinaires et de rechercher des octets nuls pour séparer les enregistrements. Dans un fichier texte sans octets nuls (c'est-à-dire le cas typique), grep -ztraitera le fichier entier comme une seule ligne. Donc (1) cela soulève la question de savoir comment il peut gérer de gros fichiers, et (2) s'il trouve une correspondance, il écrira le fichier entier, sans donner d'indice quant à l'emplacement de la correspondance. Aussi (3) le PO a dit: «idéalement, traiter toute séquence d'espace blanc comme un seul espace», vous devez donc utiliser \s+et ajouter -E.
G-Man dit «Réinstalle Monica»

1
@ G-Man Merci pour vos commentaires. Veuillez voir la réponse modifiée.
Costas

1
(0) Ah -o; J'oublie toujours ça. Une façon intelligente de l'utiliser. (1) Votre nouvelle grepréponse commence ^[\n]*; c'est une faute de frappe pour [^\n]*. (2) J'ai dit \s+délibérément.  be\s*littlecorrespondra belittleet care\s*lesscorrespondra careless. Mais je suppose que c'est un problème mineur. Et, si vous ne voulez pas utiliser -E, vous pouvez utiliser « la version du pauvre » de \s+, à savoir \s\s*. (3) Belle sedcommande. Il peut échouer s'il y a des lignes vides (la phrase de quatre mots peut donc s'étaler sur plus de quatre lignes); J'ai pu résoudre ce problème en ajoutant s/\n\s*\n/\n/.
G-Man dit `` Réinstalle Monica ''

@ G-Man Merci againg. Vos commentaires sont très utiles. J'ai essayé de publier du code plus ou moins portable car des membres célèbres me poussent à chaque fois à le faire. Quoi qu'il en soit, même sans -Evous en acier en mesure d'utiliser +en \s\+forme. Les lignes vides à l'intérieur du motif semblent être artificielles.
Costas

Je pensais à des documents texte paginés, comme les RFC - ISTR que les pages de manuel ressemblent à cela sur certains systèmes (ou l'ont fait ) - mais, après réflexion, il me semble que la plupart de ces documents ont des en-têtes et / ou des pieds de page (s) qui devraient être supprimés avant de pouvoir leur espérer grepdes phrases.
G-Man dit `` Réintègre Monica ''

7

Essaye ça:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT

Dois-je taper \s5 fois si je recherche "c'est un motif très long"?
Nikana Reklawyks

1
Oui: le point \scorrespond aux espaces, et la nouvelle ligne est un "espace".
lcd047

Je veux dire, que faire si le fichier est This\nis a very\nlong pattern, et je ne sais pas où les sauts de ligne pourraient se produire. Je devrais chercher This\sis\sa\svery\slong\spattern, non? (qui devient fastidieux à mesure que la longueur du motif augmente ou est collée d'ailleurs)
Nikana Reklawyks

2
Ensuite , vous le faites comme ceci: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
lcd047
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.