Como formatar um loop bash usando sed, awk, grep e wc

2

Portanto, eu tenho um arquivo de texto que preciso extrair linhas específicas e contar o número de vezes que um número em uma coluna específica é exibido. Eu tenho cerca de 100 ou mais desses arquivos. Eu posso fazê-lo em pequenos passos, mas quero fazê-lo usando bash / ksh:

foreach i *h3
sed '4p;55p;77q;d' $i >> output.txt
end 

^^^^ isso apenas extrairá as linhas que eu preciso de cada arquivo h3

awk '{print $6}' output.txt | grep 'P2' | wc -l

^^^ isso apenas extrairá a coluna 6 do output.txt e contará o número de vezes que P2 aparece na coluna 6

Existe uma maneira de combinar tudo isso em um script bash / ksh?

    
por e1v1s 19.05.2016 / 15:38

4 respostas

3

Se eu entendi corretamente:

  • você quer contar quantas vezes há "P2" em qualquer lugar dentro do 6º campo das linhas 4,55 e 77 de alguns arquivos (chamados * h3)?

Você pode fazer isso com 1 awk:

awk '
( FNR==4 || FNR==55 || FNR==77 ) {
    if ( $6 ~ "P2" ) { occurence++ } 
}
END {
    printf "There was: %d P2 ", occurence
    printf " among the 6th field on lines 4,55 or 77 of the *h3 files\n"
}' *h3

Observação: altere $6 ~ "P2" para $6 == "P2" se você quiser uma correspondência exata (em vez de um grep, como você usou em seu próprio exemplo, para que também corresponda a: somethingP2otherthing e suas variantes)

FNR = Número de Registros do Arquivo = número de linhas no arquivo atual (isto é, começa novamente em 1 na primeira linha de cada arquivo)  (Arquivo atual cujo nome também pode ser conhecido pela variável interna: FILENAME)

(NR = aqui não funcionaria, pois é o número (total) ou registros lidos desde o início (não desde o início do arquivo atual))

    
por 19.05.2016 / 16:02
2

Claro. Aqui está uma maneira

p2_count=0
for f in *h3; do
    for ((n=1; n<=77; n++)); do
        IFS= read -r line
        if [[ $n == 4|55|77 ]]; then
            echo "$line"
            set -f
            set -- $line
            set +f
            if [[ $6 == *P2* ]]; then
                ((p2_count++))
            fi
        fi
    done < "$f"
done > output.txt
echo "saw P2 in 6th column $p2_count times"
    
por 19.05.2016 / 15:50
0

Ou usando um bash one-liner:

for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}' | grep 'P2'; done | wc -l

Ou mais curto usando grep -c :

for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}'; done | grep -c 'P2'
    
por 19.05.2016 / 17:38
0

Normalmente, quando uma pergunta pergunta "como eu processo um monte de arquivos de texto usando ferramenta (s) específica (s) em um loop bash?", a resposta é: em parte, "Não use um loop bash, use (algumas ou todas) a própria ferramenta". Às vezes, parte da resposta é "Não use essas ferramentas, use isso".

O que você quer pode ser feito com awk sozinho, sem necessidade de um loop de shell. Ou sed ou grep ou wc :

awk 'BEGIN {OFS="\t"}
     FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++}
     ENDFILE { print FILENAME, count; count=0 }' *h3

Observação: ENDFILE é específico do GNU awk . Não funcionará com outras versões de awk .

E esta versão também imprime um total acumulado para todos os arquivos:

awk 'BEGIN {OFS="\t"}
     FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++; total++}
     ENDFILE { print FILENAME, count; count=0 }
     END { print "---", total,"total" }' *h3

O bloco END{} imprime o total e também faz uma tentativa grosseira de distinguir o total real de qualquer arquivo que tenha o nome de arquivo "total". Isso é feito imprimindo --- no primeiro campo, depois o total e, em seguida, a string total no terceiro campo. Isso está longe de ser perfeito, mas é bom o suficiente em muitos casos. É melhor do que, como wc , não fazer a tentativa.

    
por 20.05.2016 / 05:20