Compter les lignes entre les «X»

13

Je veux compter les lignes entre "X". C'est juste un exemple; Je dois appliquer le code à un résultat biologique complexe. Je serai reconnaissant si vous pouvez suggérer une commande, de préférence en utilisant awk, grepou sedcomme je les connais.

Exemple:

X
Y
Y
Y
X
Y
Y
Y
Y
X
Y
X

Sortie désirée:

3
4
1
Rhea
la source
2
Vous pourriez être intéressé par la bioinformatique si vous travaillez dans ce domaine.
terdon

Réponses:

13

Avec awk:

$ awk '!/X/{count++}/X/{print count; count = 0}' input

3
4
1

Incrémentez un décompte pour chaque ligne ne contenant pas X; imprimer et réinitialiser le nombre de lignes contenant X.

muru
la source
2
Si la première ligne n'était pas un X, le premier nombre de lignes serait toujours compté et généré avec cette solution, jusqu'à ce que la première ligne avec Xsoit mise en correspondance. EX (ne peut pas ajouter de nouvelles lignes dans les commentaires, mais considérez qu'il y a une nouvelle ligne entre chaque caractère; P): Y X Y Y X Y Y Yafficherait:1 2
Dan
1
@muru cela ne fonctionnera pas s'il n'y avait pas de X à la fin (besoin d'ajouter END{if (count)print count}), et la production d'une ligne vide où X était en début pour éviter que vous puissiez ajouter /X/&&counten condition également
αғsнιη
1
Il h. Un commentaire se plaint que les Ys en tête ne doivent pas être comptés car ils ne sont pas exactement entre deux Xs; l'autre se plaint que les Ys finaux ne sont pas comptés car ils ne sont pas exactement entre deux Xs. J'attendrai l'OP pour clarifier, si nécessaire; Je suis d'accord avec cette réponse telle qu'elle est jusque-là.
muru
12
$ awk '/X/ && prev{print NR-prev-1} /X/{prev=NR}' file
3
4
1

Comment ça fonctionne:

Awk lit implicitement les fichiers d'entrée ligne par ligne.

  • /X/ && prev{print NR-prev-1}

    Pour toute ligne contenant Xet si nous avons précédemment attribué une valeur à prev, imprimez le numéro de la ligne actuelle NR, moins prevmoins un.

  • /X/{prev=NR}

    Pour toute ligne qui contient X, définissez la variable prevau numéro de ligne en cours, NR.

John1024
la source
4
Huh, chouette. Abuser NRme donne une idée:awk '/X/{print NR - 1; NR = 0}' foo
muru
Merci, cela me donne les informations exactes. ce qui est requis.
Rhea
Muro: agréable et délicat. Sauf pour l'impression d'une valeur de trop, cela fonctionne pour moi sous gawk et mawk. Je suis curieux de savoir s'il s'agit d'un comportement garanti. @EdMorton?
John1024
3
@rhea Sauf si votre première ligne est toujours un X, il y a une petite différence dans la sortie entre les 2 réponses comme je l'ai expliqué dans un commentaire sous la réponse de muru.
Dan
1
@ John1024 merci! J'espère que cela m'aidera.
Rhea
6

Une autre awkapproche simple qui fonctionne sur les échantillons de données OP et si elle Xn'était pas dans le premier ou même dans les derniers X ou répétés.

awk -v RS='X' 'NF{print NF}' infile

Au- dessus est correct quand il n'y a qu'un seul champ dans chaque ligne par défaut FS toutes les espaces blancs , sinon ci - dessous est révisée en cas général pour le comptage linewise . Vous pouvez entrer votre MOTIF en place de X là.

awk -F'\n' -v RS='X' 'NF>2{print NF-2}'

Exemple d'entrée:

X
Y YYY Y
YY
YY Y YY YY Y Y
X
Y Y Y
X
Y
Y
X
X

La sortie est:

3
1
2
αғsнιη
la source
1

La plupart des réponses correspondent au contenu de la ligne à compter à l'aide d'expressions régulières intégrées au programme Awk. Si vous devez faire correspondre des lignes avec du contenu qui peut contenir des caractères spéciaux (soit pour Awk ou des expressions régulières), il serait préférable de comparer réellement les chaînes pour l'égalité. Par conséquent, je propose le script Awk suivant comme variante de la réponse de muru :

BEGIN {
    count = 0;
}

{
    if ($0 == needle) {
        if (count) {
            print count;
            count = 0;
        }
    } else {
        count++;
    }
}

Stockez-le sous forme de fichier texte, par exemple count-rows.awk, et invoquez-le comme suit:

awk -f count-rows.awk -v needle=X input

Vous pouvez ajuster la valeur de needleà votre guise. L'avantage de cette méthode est que vous pouvez appeler le programme à partir d'un script shell avec une valeur arbitraire pour needlesans échapper aux problèmes:

awk -f count-rows.awk -v needle="$needle" input
David Foerster
la source