Contar líneas entre "X" s

13

Quiero contar las líneas entre "X" s. Esto es solo un ejemplo; Tengo que aplicar el código a un resultado biológico complejo. Le agradeceré si puede sugerir algún comando, preferiblemente usando awk, grepo sedcomo estoy familiarizado con ellos.

Ejemplo:

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

Salida deseada:

3
4
1
ñandú
fuente
2
Puede que le interese la bioinformática si va a trabajar en este campo.
terdon

Respuestas:

13

Con awk:

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

3
4
1

Incremente un conteo por cada línea que no contenga X; imprimir y restablecer el recuento de líneas que contienen X.

muru
fuente
2
Si la primera línea no fuera un X, el primer número de líneas aún se contaría y generaría con esta solución, hasta que la primera línea Xcoincida. EX (No se pueden agregar nuevas líneas en los comentarios, pero considere que hay una nueva línea entre cada carácter; P): Y X Y Y X Y Y Ygeneraría:1 2
Dan
1
@muru, esto no funcionará si no había una X al final (es necesario agregar END{if (count)print count}), y al producir una línea vacía donde X estaba en el inicio para evitar, también puede agregar la /X/&&countcondición
αғsнιη
1
Je Un comentario se queja de que los Ys iniciales no deben contarse porque no están exactamente entre dos Xs; el otro se queja de que los Ys finales no se cuentan porque no están exactamente entre dos Xs. Esperaré a que el OP se aclare, si es necesario; Estoy bien con esta respuesta tal como es hasta entonces.
muru
12
$ awk '/X/ && prev{print NR-prev-1} /X/{prev=NR}' file
3
4
1

Cómo funciona:

Awk lee implícitamente los archivos de entrada línea por línea.

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

    Para cualquier línea que contenga Xy si previamente le hemos asignado un valor prev, imprima el número de la línea actual NR, menos prevmenos uno.

  • /X/{prev=NR}

    Para cualquier línea que contenga X, establezca la variable prevdel número de línea actual, NR.

John1024
fuente
44
Huh, bien Abusar NRme da una idea:awk '/X/{print NR - 1; NR = 0}' foo
muru
Gracias, me da la información exacta. que se requiere
Rea
Muro: Agradable y complicado. Excepto por imprimir un valor demasiado, funciona para mí bajo gawk y mawk. Tengo curiosidad por saber si esto es un comportamiento garantizado. @EdMorton?
John1024
3
@rhea A menos que su primera línea sea siempre un X, hay una pequeña diferencia en el resultado entre las 2 respuestas como lo expliqué en un comentario debajo de la respuesta de muru.
Dan
1
@ John1024 gracias! Espero que me ayude.
Rhea
6

Otro awkenfoque simple que funciona en los datos de muestra de OP y si Xno estaba en la primera o incluso en las últimas X repetidas.

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

Arriba es correcto cuando solo hay un campo en cada línea con FS por defecto cualquier espacio en blanco , de lo contrario, a continuación se revisa en el caso general para contar linealmente . Puede ingresar su PATRÓN en lugar de X allí.

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

Entrada de muestra:

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

El resultado es:

3
1
2
αғsнιη
fuente
1

La mayoría de las respuestas aquí coinciden con el contenido de la línea a contar utilizando expresiones regulares incrustadas en el programa Awk. Si necesita hacer coincidir líneas con contenido que puede contener caracteres especiales (ya sea Awk o expresiones regulares), sería mejor comparar las cadenas para la igualdad. Por lo tanto, propongo el siguiente script Awk como una variante de la respuesta de muru :

BEGIN {
    count = 0;
}

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

Almacénelo como un archivo de texto, por ejemplo count-rows.awk, e invoquelo de la siguiente manera:

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

Puede ajustar el valor needlea su gusto. La ventaja de este método es que puede invocar el programa desde un script de shell con un valor arbitrario needlesin problemas:

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