Afficher tout le fichier jusqu'au match


71

grep --before-context 5 montre 5 lignes avant le match.

Je veux tout montrer avant le match.
Cela grep --before-context 99999999fonctionnerait, mais ce n'est pas très ... professionnel.

Comment afficher tout le fichier jusqu'au match?

Réponses:


95

Sed est mieux pour ça.

Il suffit de faire:

sed '/PATTERN/q' FILE

Cela fonctionne comme ceci:

Pour chaque ligne, on regarde si elle correspond /PATTERN:

  • si oui, on l'imprime et on quitte
  • sinon, on l'imprime

C'est la solution la plus efficace, car dès qu'elle voit PATTERN, elle se ferme. Sans cela q, sed continuerait à lire le reste du fichier et ne ferait rien avec. Pour les gros fichiers, cela peut faire la différence.

Cette astuce peut également être utilisée pour émuler head:

sed 10q FILE

Juste essayé, il sort juste la première ligne du fichier ... même si match est à la ligne 38.
Nicolas Raoul

Fonctionne bien pour moi. Pouvez-vous donner un exemple d'entrée et de sortie réelles? Et la commande que vous exécutez telle quelle.
Mikel

J'avais essayé votre commande avant de la modifier, elle était: sed '/ PATTERN / p; q' FILE
Nicolas Raoul Le

7
Que dois-je faire si je ne veux pas imprimer la ligne avec le motif recherché?
tommy.carstensen

4
@ tommy.carstensen: sed '/PATTERN/Q' FILEignorera la ligne correspondante. Qest une extension GNU, donc cela ne fonctionnera pas avec sed.
Alex O

37

sed peut remplacer la plupart des fonctionnalités de grep.

sed -n '1,/<pattern>/ p' <file>

Cela signifie que l’impression commence à la première ligne jusqu’à ce que le motif corresponde.

Quelques exemples de gamme

sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2

3
Cette commande est bonne, mais vous pouvez faire mieux. De cette façon, il lit l'intégralité du fichier, mais il est possible de quitter dès qu'il a trouvé une correspondance.
Mikel

3
Que dois-je faire si je ne veux pas imprimer la ligne avec le motif recherché?
tommy.carstensen

34

imprimer jusqu'au match inclus:

awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename

imprimer jusqu'à MAIS sans inclure le match:

awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename

11
Qest cool mais spécifique au gnou, sed -n '/pattern/!p;//q'serait plus portable.
don_crissti

@don_crissti: vous devriez y répondre, je pense que c'est une bonne question (: je suis un peu curieuse de savoir comment cela fonctionne. Je pense que !cela ps'applique aux lignes ne correspondant paspattern , mais //qcela
m'embrouille

2
@don_crissti: ah, je l'ai compris - //signifie "expression régulière précédente" (je pensais que cela signifiait "faire correspondre la chaîne vide"). Je pense qu'une version plus courte de la même solution est sed -n '/pattern/q;p:?
Jwd

@ jwd - en effet, c'est plus court. 👍
don_crissti

1

Les grepméthodes GNU pures suivantes ne sont pas efficaces.

Recherchez tout jusqu'à la première instance de la chaîne " foo " dans la barre de fichiers , en utilisant trois grepmots:

grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar

Correspondant à la dernière instance de " foo ":

grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar

Remarque: les détails sur le dernier greppeuvent être trouvés dans: Regex (grep) pour la recherche multiligne nécessaire .


Pourquoi voudrait-on jamais utiliser 7 greps (+ pcre) quand il s’agit simplement de lancer une seule sedinvocation: sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'??
don_crissti

@don_crissti, votre sedcode semble avoir sa propre réponse, ou pourrait être ajouté à l'un des autres. Re 7 greps: Parce qu'il n'y avait pas de grepréponse ... (plus, la réponse aide montre pourquoi pas.)
agc

Ce n'est pas mon code, il suffit de cliquer dessus ... Même s'il s'agissait de mon code, il ne répond pas au Q ici, je ne le posterais donc pas comme réponse.
don_crissti

1

Ajoutant à la réponse de Mikel ci-dessus ...


Pour imprimer toutes les lignes jusqu'à, mais sans inclure , la première ligne FILEcontenant PATTERN, essayez:

  • sed '/.*PATTERN.*/{s///;q;}' FILE

Cela correspond à la ligne entière contenant le motif, le remplace par une ligne vierge, puis se ferme sans traiter le reste du fichier.


Post-script:

Le moyen le plus simple et le plus clair que je pouvais imaginer pour empêcher l’impression d’une nouvelle ligne supplémentaire à la fin (sans faire appel à un autre outil) était de lancer à nouveau sed et de supprimer la nouvelle ligne finale:

sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'

... et puisque nous supprimons cette ligne de toute façon, nos travaux précédents sont redondants et nous pouvons simplifier pour:

sed '/PATTERN/q' FILE | sed '$d'

La réponse de Glenn - et mon commentaire là-bas - montre comment le faire avec une seule sedinvocation.
don_crissti

(Merci pour cela - j'ai vu votre commentaire sur la réponse de agc, mais j'ai raté l'autre ou l'a simplement écrémé parce que mon cerveau n'aimait pas les doubles négations.) Comme je l'utilisais à la fois en a tcshet en bashalias, je devais m'assurer que je avait une solution monoligne relativement concise qui fonctionnait à la fois en version standard et GNU sed(pour la portabilité); toutes les exigences que votre contribution peut très bien avoir satisfait. En tant que personne qui utilise sed très rarement, mon exigence la plus importante concernait quelque chose que je pouvais comprendre rapidement lorsque je souhaitais la modifier ou la réutiliser facilement dans des années.
Jim Grisham

1

Pour les personnes qui choisissent de ne retenir que les outils de base du travail quotidien et qui souhaitent accepter des solutions moins élégantes et moins efficaces:

head -n $(grep -n pattern filename | cut -d: -f1) filename

Si cette commande concerne un script, je rechercherai des solutions plus élégantes (et éventuellement plus efficaces). S'il s'agit d'une commande unique ou d'un script à jeter, je m'en fiche.


1
Belle idée, mais trois commandes quand on fera.
Mikel

1
Connaître les bases est très bien. Connaître le bon outil pour le travail est meilleur, cependant.
Soulmerge

Si cette commande concerne un script, je rechercherai des solutions plus élégantes (et éventuellement plus efficaces). S'il s'agit d'une commande unique (ou d'un script à jeter), cela ne me dérange pas.
Lesmana

0

Vous pouvez également utiliser l'un des éléments suivants

tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac 

ou

tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac

ou

tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac

La première option est très similaire à celle suggérée par le PO, elle s'assure seulement de montrer suffisamment de lignes avant le contexte en comptant les lignes du fichier.

La deuxième option recherche le numéro de ligne de la première correspondance (vous pouvez également changer cela en modifiant la "tête" intérieure) et utilise ensuite tête sur ce numéro.

La dernière option remplace toutes les nouvelles lignes par la correspondance et que remplace deux correspondances adjacentes par une nouvelle ligne. La sortie de ceci est une ligne pour chaque bloc de texte entre deux correspondances. Après cela, il utilise 'head' pour choisir la première ligne (lier le bloc de texte jusqu'à la première correspondance) et reconvertit chaque correspondance en une nouvelle ligne. cette option ne fonctionne que si le fichier est au format suivant

pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern 
texttexttext
texttexttexttexttexttexttexttexttext

et ainsi de suite


2
Pensez à expliquer comment cela fonctionne, en particulier parce que cette sedcommande au bas de la page est un peu maladroite.
Strugee

la première option est très similaire à celle suggérée par le PO, mais elle permet de s'assurer de montrer suffisamment de kines avant le contexte en comptant les lignes dans le fichier,
user122778
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.