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

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

Portanto, tenho um arquivo de texto do qual preciso extrair linhas específicas e contar o número de vezes que um número em uma coluna específica aparece. Eu tenho cerca de 100 desses arquivos. Posso fazer isso em pequenos passos, mas quero fazer isso usando bash/ksh:

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

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

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

^^^ isso apenas extrairá a coluna 6 de 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?

Responder1

Se bem entendi:

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

Você poderia 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

Nota: mude $6 ~ "P2"para $6 == "P2"se quiser uma correspondência exata (em vez de grep, como você usou em seu próprio exemplo, para que também corresponda a: somethingP2otherthinge suas variantes)

FNR = Número de registros do arquivo = número de linhas do arquivo atual (ou seja, 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))

Responder2

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"

Responder3

Ou usando umfestauma linha:

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'

Responder4

Normalmente, quando uma pergunta pergunta "como faço para processar vários arquivos de texto usandoferramentas específicasem um loop bash?", a resposta é, em parte, "Não use um loop bash, use (algumas ou todas) as próprias ferramentas". Às vezes, parte da resposta é até "Não use essas ferramentas, use-as".

O que você deseja pode ser feito awksozinho, sem necessidade de um shell loop. Ou sedou grepou wc:

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

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

E esta versão também imprime um total cumulativo 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 END{}bloco imprime o total e também faz uma tentativa grosseira de distinguir o total real de quaisquer arquivos que tenham o nome de arquivo "total". Isso é feito imprimindo ---no primeiro campo, depois o total e depois a string totalno terceiro campo. Isso está longe de ser perfeito, mas é bom o suficiente em muitos casos. É melhor do que, tipo wc, não tentar.

informação relacionada