Comment imprimer toutes les lignes après une correspondance jusqu'à la fin du fichier?


48

Le fichier d'entrée 1 est:

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Je donne à la correspondance le motif de dans other file(comme à dog 123 4335partir de fichier2).

Je fais correspondre le motif de la ligne dog 123 4335et après avoir imprimé toutes les lignes sans ligne de correspondance, ma sortie est:

cat 13123 23424
deer 2131 213132
bear 2313 21313

Si uniquement utiliser sans adresse de ligne, utilisez uniquement le motif, par exemple, 1s comment faire correspondre et imprimer les lignes?


Un autre fichier peut-il contenir un seul motif à rechercher, ou un par ligne, et commencer à chercher quelle que soit la ligne trouvée en premier dans le fichier recherché?
Ciro Santilli a annoncé le 14 sep16

Réponses:


27

En supposant que vous souhaitiez faire correspondre toute la ligne à votre modèle, avec GNU sed, cela fonctionne:

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

Équivalent standard:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

Avec l'entrée suivante ( infile):

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

La sortie est:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

Explication:

  • /^dog 123 4335$/ recherche le motif désiré.
  • :a; n; p; ba;est une boucle qui extrait une nouvelle ligne de input ( n), l’imprime ( p) et la ramène à l’étiquette a :a; ...; ba;.

Mise à jour

Voici une réponse qui se rapproche de vos besoins, c'est-à-dire un motif dans file2, en allant de fichier1

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

Les commandes grep et cut incorporées trouvent la première ligne contenant un motif de fichier2, ce numéro de ligne plus un est transmis à la fin, le plus un permettant de sauter la ligne contenant le motif.

Si vous voulez commencer à partir du dernier match au lieu du premier, ce serait:

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

Notez que toutes les versions de tail ne prennent pas en charge la notation plus.


C’est le premier exemple des commandes n et p dans sed que j’ai vu et qui n’a pas l’impression de pousser sed trop loin. D'après mes brefs tests, il semble que sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(avec le p et le n commutés) inclut avec succès la ligne qui correspond également.
Josiah Yoder

26

Si vous avez un fichier raisonnablement court, grepseul pourrait fonctionner:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

5000 est juste ce que je pense de "raisonnablement court", car greptrouve la première correspondance et la sort avec les 5000 prochaines lignes (le fichier n'en a pas besoin souvent). Si vous ne voulez pas le match lui-même, vous devrez le couper, par exemple

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


Si vous ne voulez pas le premier mais le dernier match comme délimiteur, vous pouvez utiliser ceci:

tac animals.txt | sed -e '/dog 123 4335/q' | tac

Cette ligne lit animals.txtdans l’ordre inverse des lignes et en sort jusqu’à la ligne incluse dog 123 4335, puis s’inverse de nouveau pour rétablir le bon ordre.

Encore une fois, si vous n'avez pas besoin de la correspondance dans le résultat, ajoutez la queue. (Vous pouvez également compliquer l’expression sed pour se débarrasser de son tampon avant de quitter.)


D'après mon test, GNU grep 3.0 ne génère pas plus de 132 lignes dans le contexte postérieur (quelle que soit la valeur spécifiée).
Ruvim

22

Dans la pratique, j'utiliserais probablement la réponse d'Aet3miirah la plupart du temps et celle d' Alexey est merveilleuse lorsque l'on souhaite naviguer à travers les lignes (cela fonctionne également avec less). OTOH, j'aime vraiment une autre approche (qui est un peu la réponse inversée de Gilles :

sed -n '/dog 123 4335/,$p'

Lorsqu’il est appelé avec l’ -nindicateur, sedn’imprime plus par défaut les lignes qu’il traite. Ensuite, nous utilisons un formulaire à 2 adresses qui dit d’appliquer une commande depuis la ligne correspondant /dog 123 4335/à la fin du fichier (représenté par $). La commande en question est p, qui affiche la ligne en cours. Donc, cela signifie "imprimer toutes les lignes depuis celle qui correspond /dog 123 4335/jusqu'à la fin".


3
Cela imprime la dogligne, ce qui n'est pas voulu ici.
Stéphane Chazelas

1
Cela semble être la meilleure solution (et fonctionne dans mon cas), mais il faudrait également l'adapter pour ignorer la ligne correspondante.
Pavel Šimerda

1
sed -n '/ dog 123 4335 /, $ p' | sed '1d' va enlever la lignée de chien
Kemin Zhou

1
sed -n '/dog 123 4335/,$p' | tail -n +2éliminera aussi le match
gilad mayani

15
sed -e '1,/dog 123 4335/d' file1

Si vous avez besoin de lire le modèle depuis un fichier, remplacez-le par la commande sed. Si le fichier contient un motif sed:

sed -e "1,/$(cat file2)/d" file1

Si le fichier contient une chaîne littérale à rechercher, citez tous les caractères spéciaux. Je suppose que le fichier contient une seule ligne.

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

Si vous voulez que la correspondance soit toute la ligne, pas seulement une sous-chaîne, insérez le motif dans ^…$.

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1

6
Cela ne fonctionnera pas si le motif est sur la première ligne. GNU seda 0,/dog.../dpour cela.
Stéphane Chazelas

14

$ more +/"dog 123 4335" file1


4
Cela fonctionne aussi avec less.
brandizzi

3
astucieux sur le terminal, mais ça ne marche pas si vous le dirigez vers autre chose tac.
jcomeau_ictx

Je l'utilise comme ça, $ more + / "correspondre à mes mots" file1 >> file2
AMB

1
Peut-être a +été remplacé par -pdans POSIX 7: pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html mais pas encore implémenté dans util-linux 2.20.1. Et cela imprime aussi skipping..et quelques nouvelles lignes supplémentaires (à stderr je pense, donc ça pourrait aller).
Ciro Santilli a annoncé le 14 sep16

peut-être que les choses ont changé depuis? mon commentaire a eu 3 votes positifs, donc il aurait pu être pertinent à l'époque ...
jcomeau_ictx

11

Avec awk:

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"

5

Une façon d'utiliser awk:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

où fichier2 contient vos modèles de recherche. Tout d'abord, tout le contenu de file2 est stocké dans le tableau "a". Lorsque le fichier1 est traité, chaque ligne est comparée au tableau et imprimée uniquement si elle n’est pas présente.


Je pense que l'OP veut sortir chaque ligne en suivant le modèle.
Thor

@Thor: merci de l'avoir signalé, mis à jour maintenant ...
Gourou

Bien fait :).
Thor

5

Si l'entrée est un fichier régulier lseekable :

Avec GNU grep:

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

Avec sed:

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

Un GNU grepappelé w / l’ -moption quittera l’entrée lors du match - et laissera son entrée (lseekable) fd immédiatement après le point où il a trouvé son dernier match. Donc, appeler grepw / -m1trouve la première occurrence d’un motif dans un fichier et laisse l’offset en entrée précisément au bon endroit pour cattout écrire après la première correspondance du motif dans un fichier sur la sortie standard.

Même sans GNU, grepvous pouvez faire exactement la même chose avec un compatible POSIX sed- quand vous sed qspécifiez, il est spécifié de laisser son décalage d'entrée là où il le fait. GNU sedn'est pas conforme aux normes de cette manière, cependant, et donc ce qui précède ne fonctionnera probablement pas avec GNU à sedmoins que vous ne l'appeliez avec son -ucommutateur.


Il est à noter que le sedpartage de flux démontré ici ne constitue pas spécialement (bien que, oui, la norme référencée donne spécifiquement l'exemple en sedtant qu'utilitaire capable de fonctionner) du flux de travaux de forme libre et de coopération conditionnelle indiqué. notamment, tous les utilitaires standard sont conçus et spécifiés pour coopérer et ainsi partager les positions de curseur des flux d’entrée sans que le lecteur suivant ne manque de traitement. grep -qdevrait le faire; tranquillement grepdevrait revenir dès qu'une correspondance est trouvée dans l'entrée, et tout reste d'entrée ne devrait pas, selon la norme, être consommé par défaut.
mikeserv

4

Ma réponse à la question dans le sujet, sans stocker le motif dans un deuxième fichier. Voici mon fichier de test:

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

Variante Perl avec motif dans un fichier:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

2

Avec ed:

ed -s file1 <<< '/dog 123 4335/+1,$p'

Cela envoie une pcommande rint à ed dans une chaîne ici; la commande d'impression est limitée à un après ( +1) la dog 123 4335correspondance jusqu'à la fin du fichier ( $).


1

Si la création d'un fichier temporaire ne vous dérange pas et si vous en avez csplit, cela fonctionne:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

Note file1est le fichier d'entrée et file2le fichier de motif (comme indiqué dans la question).

La forme longue de la commande ci-dessus est:

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

c'est à dire,

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplitsans le prefixdrapeau ci-dessus, le fichier serait créé xx00(le préfixe étant xxet le suffixe étant 00). Avec le drapeau ci-dessus, il crée le fichier file1_00. Sans l' quietindicateur, il affiche la taille du fichier de sortie (taille du fichier résultant).


0

Puisque awk n'est pas expressément interdit, voici mon offre en supposant que "chat" est la contrepartie.

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt

0

Comment imprimer toutes les lignes après une correspondance jusqu'à la fin du fichier?

Une autre façon de le dire est "comment supprimer toutes les lignes de la première jusqu'à la correspondance (y compris)", et cela peut être sedécrit ainsi:

sed -e '1,/MATCH PATTERN/d'

1
Le seul problème est que le motif est sur la première ligne ...
don_crissti


Je suppose que nous avons besoin d'un comité ici pour décider.
poige

1
@poige: nah, vous donnez la même réponse de manière moins complète
Thor

@don_crissti, qu'en est-il sed -e '0,/MATCH PATTERN/d'alors?
Velkan
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.