Faça um loop pelo diretório e some o valor próximo ao padrão específico produzindo uma média

Faça um loop pelo diretório e some o valor próximo ao padrão específico produzindo uma média

Quero percorrer todos os arquivos do diretório.

os arquivos estão dispostos assim:

<Overall>4
other data
<Overall>2
other data
......

Eu tenho o código:

for file in .dat; 
do
awk 'x+=sub(/<Overall>/,""){y+=$0} END{print FILENAME, y/x}' $file
done

isso imprime a média dos valores no arquivo, porém o que eu quero é pegar o diretório em que meu script está como argumento e executar o comando awk em todos os arquivos .dat do diretório.

Eu tentei usar o código:

for file in $1

mas receba o erro:

awk: cmd. line:1: fatal cannot open file `folder' for reading (No such file or directory)

Além disso, também quero poder classificar a saída dos valores médios de alto para baixo.

Responder1

Duas variações:

  1. Faça um loop nos arquivos e invoque awkuma vez para cada arquivo, ou
  2. Forneça ao awkscript todos os arquivos e deixe-o calcular a média de cada um e relatar à medida que avança.

A classificação do resultado de qualquer uma das soluções abaixo pode ser feita canalizando sua saída através

sort -k2,2rn

Isso faz uma classificação numérica reversa no segundo campo (as médias).


Primeira solução:

#!/bin/sh

for name in "$1"/*.dat; do
    test -f "$name" || continue   # skip non-files
    awk -F '>' '/<Overall>/ { s+=$NF; n++ } END { print FILENAME, s/n }' "$name"
done

Este script espera um nome de diretório na linha de comando como o primeiro e único argumento da linha de comando. O awkscript encontrará todas as linhas que contêm a string Overalle somará (in s) o valor após o> naquela linha. No final, a média é exibida junto com o nome do arquivo. A variável ncontém o número de vezes que adicionamos algo s.


Segunda solução (requer GNU Awk):

#!/bin/sh

find "$1" -maxdepth 1 -type f -name '*.dat' \
    -exec awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' {} +

Este script, como o primeiro, espera um nome de diretório como seu único argumento de linha de comando. Ele usafind para executar um awkscript com tantos .datarquivos quanto possível ao mesmo tempo.

O awkscript faz uso do GNU AwkENDFILE para gerar os valores calculados e redefinir as variáveis s​​​​e napós o processamento de cada arquivo, antes de começar a ler o próximo arquivo.

Isso também pode ter sido escrito como

#!/bin/sh

awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' "$1"/*.dat

mas isso depende de "$1"/*.datnão expandir para uma lista muito longa de nomes de arquivos (isso também exige que cada .datnome seja um arquivo normal, o que é algo que o acimafind comando acima garante -type f).

informação relacionada