Média e movimentação de uma seleção de arquivos

3

Eu tenho um monte de diretórios, cada um deles colocando uma tabela ASCII nomeada de acordo com o nome do diretório; como segue:

a1/a1.txt
a2/a2.txt
a3/a3.txt
a4/a4.txt
b1/b1.txt
b2/b2.txt
b3/b3.txt
b4/b4.txt

Gostaria de operar uma seleção acima de a e b 4 arquivos diferentes, calculando o valor médio da quarta coluna de cada arquivo a (então a1.txt a2.txt a3.txt a4.txt ) e b (so% código%); e mova a tabela com o maior valor médio para outro diretório.

Então, se:

a1.txt average value = 1
a2.txt average value = 0.25
a3.txt average value = 2
a4.txt average value = 1.15
b1.txt average value = 3
b2.txt average value = 1.7
b3.txt average value = 0.25
b4.txt average value = 2

Em seguida, b1.txt b2.txt b3.txt b4.txt e a3.txt serão movidos para um diretório distante.

Eu tenho o seguinte código:

for x in a b
do
  RESULT=$(awk '{x+=$4} END{print x/NR, FILENAME}' ${x}[1-4]/${x}[1-4].txt | sort -n -r| head -1)
  highest="$(echo $RESULT | cut -d ' ' -f1 )"
  hifile="$(echo $RESULT | cut -d ' ' -f2 )"
  echo "highest was $highest in $hifile"
  cp "$hifile" "high_dis/${x}.txt"
done

Mas esse código apenas calcula o valor médio dos quatro arquivos e depois copia o último arquivo ( b1.txt e a4.txt )

Alguém sabe como obter o resultado desejado?

    
por steve 18.11.2015 / 13:52

2 respostas

2

Seu problema foi devido ao fato de que somente depois de ler todos os arquivos de entrada, awk atinge a cláusula END .

A substituição da primeira linha do seu loop for pelo seguinte deve resolver seu problema.

RESULT=$(awk 'BEGIN{curr_f=FILENAME; nr=1} {if(curr_f!=FILENAME){if(mean > max_mean){max_mean=mean; f=curr_f} curr_f=FILENAME; nr=0; sum=0} } { sum+=$4; nr++; mean=sum/nr }  END{if(mean>max_mean){print mean, FILENAME}else{print max_mean, f}}' ${x}[1-4]/${x}[1-4].txt )
    
por 18.11.2015 / 15:57
1

Eu usaria uma abordagem ligeiramente diferente e faria mais do trabalho diretamente no awk. Primeiro, use o FNR que volta para 1 sempre que um novo arquivo é processado por awk e alimenta todos os arquivos a ou b para awk de uma vez:

$ for f in a b; do 
    awk '(FNR==1 && n>1){
            av=x/n;if(av>max){
                max=av;f=FILENAME
            }
        x=0; n=0
        }
        {x+=$4;n=FNR} 
        END{ 
            if(x/n>max){print x/n,FILENAME}
            else{print max,f}'
        } "$f"[1..4]/"$f"[1..4].txt; done
18898.4 a3.txt
18806 b4.txt

Isso nos dá os dois arquivos com a maior média. Para movê-los, você poderia simplesmente remover o valor da saída do script anterior, mantendo apenas o nome do arquivo e passá-lo diretamente para o comando cp :

$ cp -v $(for f in a b; do awk '(FNR==1 && n>1){av=x/n;if(av>max){max=av;f=FILENAME};x=0;n=0}{x+=$4;n=FNR} END{if(x/n>max) print x/n,FILENAME; else print max,f}' "$f"[1-4]/"$f"[1..4].txt; done) bar/
‘a3.txt’ -> ‘bar/a3.txt’
‘b4.txt’ -> ‘bar/b4.txt’

Observe que isso será interrompido se seus nomes de arquivos contiverem espaços em branco ou caracteres glob.

    
por 18.11.2015 / 16:32