web-dev-qa-db-fra.com

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

Le fichier d'entrée1 est:

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

Je donne au match le modèle de other file ( comme dog 123 4335 du fichier2).

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

cat 13123 23424
deer 2131 213132
bear 2313 21313

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

52
loganaayahee

En supposant que vous voulez faire correspondre la ligne entière avec 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 souhaité.
  • :a; n; p; ba; est une boucle qui récupère une nouvelle ligne depuis l'entrée (n), l'imprime (p) et se ramifie pour étiqueter un :a; ...; ba;.

Mise à jour

Voici une réponse qui se rapproche le plus de vos besoins, c'est-à-dire le modèle dans le fichier2, la récupération à partir du fichier1:

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

Le grep et le cut intégré trouvent la première ligne contenant un motif du fichier2, ce numéro de ligne plus un est transmis à la queue, le plus est là pour sauter la ligne avec le motif.

Si vous voulez commencer à partir du dernier match au lieu du premier match, 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.

29
Thor

Si vous avez un fichier raisonnablement court, grep seul pourrait fonctionner:

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

5000 est juste ma supposition à "raisonnablement court", car grep trouve la première correspondance et la sort avec les 5000 lignes suivantes (le fichier n'a pas besoin d'en avoir autant). 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

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

Cette ligne indique animals.txt dans l'ordre inverse des lignes et des sorties jusqu'à et y compris la ligne avec dog 123 4335 puis inverse à nouveau pour rétablir l'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 supprimer son tampon avant de quitter.)

27
Aet3miirah

Dans la pratique, j'utiliserais probablement la réponse d'Aet3miirah la plupart du temps et la réponse d'Alexey est merveilleux lorsque vous souhaitez naviguer à travers les lignes (également, cela fonctionne également avec less). OTOH, j'aime vraiment une autre approche (qui est en quelque sorte l'inverse réponse de Gilles :

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

Lorsqu'il est appelé avec le -n flag, sed n'imprime plus par défaut les lignes qu'il traite. Ensuite, nous utilisons un formulaire à 2 adresses qui dit d'appliquer une commande à partir de la ligne correspondant à /dog 123 4335/ jusqu'à la fin du fichier (représenté par $). La commande en question est p, qui imprime la ligne courante. Donc, cela signifie "imprimer toutes les lignes de celle correspondant à /dog 123 4335/ jusqu'à la fin."

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

Si vous devez lire le modèle à partir d'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 la ligne entière, pas seulement une sous-chaîne, enveloppez le motif dans ^…$.

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

$ more +/"dog 123 4335" file1

14
alexey

Avec awk:

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

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

Une GNU grep appelée avec l'option -m Quittera l'entrée lors de la correspondance - et laissera son (lseekable) entrée fd immédiatement après la point, il a trouvé son dernier match. Donc, appeler grep w/-m1 Trouve la première occurrence d'un modèle dans un fichier et laisse le décalage d'entrée exactement au bon endroit pour que cat écrive tout ce qui suit le modèle. première correspondance dans un fichier avec stdout.

Même sans GNU grep, vous pouvez faire exactement la même chose avec un compatible POSIX sed - lorsque sedq est activé, il est spécifié pour laisser son décalage d'entrée là où il le fait. GNU sed n'est pas conforme aux normes de cette manière, cependant, et donc ce qui précède ne fonctionnera probablement pas avec un GNU sed à moins que vous ne l'appeliez avec son Commutateur -u.

5
mikeserv

Une façon d'utiliser awk:

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

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

5
Guru

Ma réponse à la question dans le sujet, sans stocker de 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
4
jbgood

Avec ed:

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

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

2
Jeff Schaller

Si cela ne vous dérange pas de créer un fichier temporaire et que csplit soit disponible, cela fonctionne:

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

Remarque file1 est le fichier d'entrée et file2 est le fichier de signatures (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"

csplit sans l'indicateur prefix ci-dessus créerait le fichier xx00 (le préfixe étant xx et le suffixe étant 00). Avec le drapeau ci-dessus, il crée le fichier file1_00. Sans l'indicateur quiet, il imprime la taille du fichier de sortie (taille du fichier résultant).

1
YenForYang

Depuis awk n'est pas expressément interdit, voici mon offre en supposant que "chat" est le match.

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

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 1ère jusqu'à la correspondance (y compris)", et cela peut être sed - écrit comme:

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