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?
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
/^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;
.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.
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.)
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."
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
Avec awk
:
awk 'BEGIN {getline pattern < "other file"}
NR == 1, $0 ~ pattern {next}; {print}' < "input file"
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 sed
q
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
.
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.
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
Avec ed
:
ed -s file1 <<< '/dog 123 4335/+1,$p'
Cela envoie une commande p
rint à 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 ($
).
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).
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
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'