Autre option :inverser le fichier et imprimer le suivant ligne si la condition correspond :
tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac
Concernant la généralité
Je pense qu'il faut mentionner que la solution la plus générale à cette classe de problème implique deux passes :
- la première passe pour ajouter un numéro de ligne décimal ($REC) au début de chaque ligne, regroupant efficacement les lignes en enregistrements par $REC
- la deuxième passe à déclencher sur la première instance de chaque nouvelle valeur de $REC en tant que limite d'enregistrement (réinitialisant $CURREC), puis en continuant dans l'idiome AWK natif concernant les enregistrements à suivre correspondant à $CURREC.
Dans le fichier intermédiaire, une séquence de chiffres décimaux suivie d'un séparateur (pour des raisons humaines, généralement une tabulation ou un espace ajouté) est analysée (c'est-à-dire coupée conceptuellement) comme hors bande par rapport au fichier de base.
Monstre de collage de ligne de commande
Même confiné à la ligne de commande, il est facile de s'assurer que le fichier intermédiaire n'arrive jamais sur le disque. Il vous suffit d'utiliser un shell avancé tel que ZSH (mon préféré) qui prend en charge la substitution de processus :
paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk
Rendons ce one-liner plus adapté à l'exposition :
P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk
Cela démarre trois processus :le script AWK en ligne trivial, paste
, et le script AWK que vous vouliez vraiment exécuter en premier lieu.
Dans les coulisses, le <()
La construction de ligne de commande crée un canal nommé et transmet le nom du canal à coller comme nom de son premier fichier d'entrée. Pour paste
du second fichier d'entrée, on lui donne le nom de notre fichier d'entrée d'origine (ce fichier est donc lu séquentiellement, en parallèle, par deux processus différents, qui en consommeront entre eux au plus un lu à partir du disque, si le fichier d'entrée est froid).
Le tube nommé magique au milieu est un FIFO en mémoire que l'ancien Unix gérait probablement à environ 16 Ko de taille moyenne (interrompant par intermittence le paste
traiter si le yourscript.awk
le processus est lent à vider ce FIFO vers le bas).
Peut-être que l'Unix moderne y ajoute un tampon plus grand parce qu'il le peut, mais ce n'est certainement pas une ressource rare dont vous devriez vous préoccuper, jusqu'à ce que vous écriviez votre premier truly ligne de commande avancée avec redirection de processus impliquant ceux-ci par centaines ou milliers :-)
Considérations supplémentaires sur les performances
Sur les processeurs modernes, ces trois processus pourraient facilement s'exécuter sur des cœurs séparés.
Les deux premiers de ces processus sont à la limite du trivial :un script AWK avec une seule correspondance de modèle et une comptabilité mineure, paste appelé avec deux arguments. yourscript.awk
aura du mal à courir plus vite que ceux-ci.
Quoi, votre machine de développement n'a pas de cœurs légèrement chargés pour rendre ce modèle de solution maître-maître presque gratuit dans le domaine d'exécution ?
Ding Dong.
Bonjour?
Hé, c'est pour toi. 2018 vient d'appeler et veut récupérer son problème.
2020 est officiellement le sursis de MTV :c'est comme ça qu'on l'aime, des tubes magiques pour rien et des noyaux gratuits. Sans parler à haute voix d'un fournisseur de puces TLA particulier qui fait vibrer l'espace ces jours-ci.
En dernier lieu, si vous ne voulez pas la surcharge liée à l'analyse des numéros d'enregistrement réels :
X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"
Maintenant, votre fichier intermédiaire in-FIFO est annoté avec seulement deux caractères supplémentaires ajoutés à chaque ligne ('0' ou '1' et le caractère de séparation par défaut ajouté par paste
), avec '1' marquant la première ligne de l'enregistrement.
FIFO nommés
Sous le capot, ce ne sont pas différents des FIFO magiques instanciés par Unix lorsque vous écrivez une commande pipe normale :
cat file | proc1 | proc2 | proc2
Trois canaux sans nom (et tout un processus consacré à cat
vous n'en avez même pas eu besoin).
C'est presque dommage que le vraiment exceptionnel la commodité des flux stdin/stdout par défaut tels que prégéré par le shell masque la réalité que paste $magictemppipe1 $magictemppipe2
ne porte aucune considération de performance supplémentaire digne de réflexion, dans 99% des cas.
"Utilisez le <()
Joint en Y, Luke."
Votre réflexe instinctif vers la décomposition sémantique naturelle dans le domaine du problème en bénéficiera énormément.
Si quelqu'un avait eu l'intelligence de nommer la construction du shell <()
en tant qu'opérateur YODA en premier lieu, je soupçonne qu'il aurait été poussé au service universel il y a au moins une bonne décennie.
Cela peut être un moyen :
$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA
Explication
$1=="BB" && $2>1 {print f}
si le 1er champ est exactementBB
et le 2ème champ est supérieur à1
, puis imprimezf
, une valeur stockée.{f=$1}
stocker la ligne courante dansf
, pour qu'il soit accessible lors de la lecture de la ligne suivante.