Contar linhas entre "X" s

13

Eu quero contar as linhas entre "X" s. Este é apenas um exemplo; Eu tenho que aplicar o código a um resultado biológico complexo. Serei grato se você puder sugerir algum comando, de preferência usando awk, grepou sedcomo eu estou familiarizado com eles.

Exemplo:

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

Saída desejada:

3
4
1
Rhea
fonte
2
Você pode estar interessado em Bioinformática se estiver trabalhando neste campo.
terdon 8/09/17

Respostas:

13

Com awk:

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

3
4
1

Incremente uma contagem para cada linha que não contém X; imprima e redefina a contagem de linhas que contêm X.

muru
fonte
2
Se a primeira linha não for uma X, o primeiro número de linhas ainda será contado e emitido com esta solução, até que a primeira linha Xseja correspondida. EX (Não é possível adicionar novas linhas nos comentários, mas considere que há uma nova linha entre cada caractere; P): Y X Y Y X Y Y Ygeraria:1 2
Dan
1
@muru isto não vai funcionar se não houvesse X no final (necessidade add END{if (count)print count}), e produzindo linha vazia onde X estava no início para evitar que você pode adicionar /X/&&countem condição também
αғsнιη
1
Heh. Um comentário reclama que Ys principais não devem ser contados porque não estão exatamente entre dois Xs; o outro reclama que Ys à direita não são contados porque não estão exatamente entre dois Xs. Vou esperar o OP esclarecer, se necessário; Estou bem com esta resposta, até então.
muru 8/09/17
12
$ awk '/X/ && prev{print NR-prev-1} /X/{prev=NR}' file
3
4
1

Como funciona:

O Awk lê implicitamente os arquivos de entrada linha por linha.

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

    Para qualquer linha que contenha Xe se tivermos atribuído um valor anteriormente prev, imprima o número da linha atual NR, prevmenos um.

  • /X/{prev=NR}

    Para qualquer linha que contenha X, defina a variável prevcomo o número da linha atual NR,.

John1024
fonte
4
Huh, legal. Abusando NRme dá uma idéia:awk '/X/{print NR - 1; NR = 0}' foo
Muru
Obrigado, me dá a informação exata. o que é necessário.
Rhea
Muro: Bom e complicado. Exceto por imprimir um valor a mais, ele funciona para mim sob gawk e mawk. Estou curioso para saber se esse é um comportamento garantido. @EdMorton?
precisa saber é o seguinte
3
@rhea A menos que sua primeira linha seja sempre uma X, há uma pequena diferença na saída entre as 2 respostas, como expliquei em um comentário na resposta de muru.
Dan
1
@ John1024 thankyou! Espero que me ajude.
Rhea
6

Outra awkabordagem simples que funciona com os dados de amostra do OP e se Xnão estava no primeiro ou mesmo no último ou repetido Xs.

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

Acima está correto quando existe apenas um campo em cada linha com FS padrão, quaisquer espaços em branco , caso contrário, a seguir é revisada em geral para contagem em linha . Você pode inserir seu PATTERN no lugar de X lá.

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

Entrada de amostra:

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

A saída é:

3
1
2
αғsнιη
fonte
1

A maioria das respostas aqui corresponde ao conteúdo da linha a ser contada usando expressões regulares incorporadas ao programa Awk. Se você precisar combinar linhas com conteúdo que possa conter caracteres especiais (para Awk ou expressões regulares), seria melhor comparar as seqüências de caracteres para obter a igualdade. Portanto, proponho o seguinte script do Awk como uma variante da resposta de muru :

BEGIN {
    count = 0;
}

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

Armazene-o como um arquivo de texto, por exemplo count-rows.awk, e chame-o da seguinte maneira:

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

Você pode ajustar o valor needleao seu gosto. A vantagem desse método é que você pode invocar o programa a partir de um script de shell com um valor arbitrário, needlesem problemas de escape:

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