Como fazer um loop para processar dois arquivos de entrada

3

Estou usando o awk para fazer corresponder dois arquivos e depois multiplicar os elementos do arquivo2 e arquivo1.

 awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
      /:/ || !NF{print; next}
     {print $1, $2*a[$1], $2*b[$1]}' file2 file1 > output

Este script processa apenas dois arquivos de entrada e produz um arquivo de saída.

Eu quero fazer um loop para usar esse script para muitos (milhares) arquivos. Eu tento fazer:

for file1 in ../mo/*e.log | 
for file2 in ../excited/*-d.log;   do
awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
     /:/ || !NF{print; next}
     {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
done

Os arquivos estão relacionados, assim como 0001e.log e 0001-d.log, 0002e.log e 0002-d.log, 0002e.log e 0002-d.log ... A saída esperada pode ser 0001f. log, 0002f.log, 0003f.log ...

Mas sem sucesso. Alguma idéia?

    
por alloppp 09.06.2016 / 16:11

3 respostas

3

Talvez você queira:

set ../mo/*e.log
for file2 in ../excited/*-d.log; do
  file1=$1; shift
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
       /:/ || !NF{print; next}
       {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
done

Ou com zsh :

file1s=(../mo/*e.log)
file2s=(../excited/*-d.log)
for file1 file2 (${file1s:^file2s}) {
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
       /:/ || !NF{print; next}
       {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
}

Acima, temos duas listas ordenadas de nomes de arquivos e passamos por ambas as listas em paralelo. Se o nome base dos arquivos em mo e em excited for correspondido, você poderia fazer:

for file1 in ../mo/*e.log; do
  basename=${file1%e.log}
  basename=${basename##*/}
  file2=../excited/$basename-d.log
  [ -f "$file2" ] || continue
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
       /:/ || !NF{print; next}
       {print $1, $2*a[$1], $2*b[$1]}' "$file1" "$file2" > "${file1%e.log}f.log"
done
    
por 09.06.2016 / 17:12
2

Experimente paste file1 file2 | tr '\t' '*' | bc > output .

Então, para o grande loop (com bash ), que alinha arquivos de ../ mo / , ../ excited / e gera produtos para a série f de arquivos numerados no diretório atual:

for f in ../mo/*e.log; do
    g=${f/mo/excited}
    o=${f##*/}
    paste $f ${g/e.log/-d.log} | tr '\t' '*' | bc > ${o/e.log/f.log} 
done

Demo, (com bash isms), imprima os quadrados de 1 a 5:

paste <(seq 5) <(seq 5) | tr '\t' '*' | bc

Saída:

1
4
9
16
25
    
por 09.06.2016 / 17:05
0

Se você tem o GNU Parallel instalado, você pode fazer:

doit() {
  file1="$1"
  file2="$2"
  output="$3"
  awk 'NR == FNR{a[$1]=$2; b[$1]=$3; next}
      /:/ || !NF{print; next}
     {print $1, $2*a[$1], $2*b[$1]}' "$file2" "$file1" > "$output"
}
export -f doit

# If all filenames fit on a command line:
parallel --xapply doit {1} {2} {1/.}{2/.}.out ::: ../mo/?*e.log ::: ../excited/?*d.log
# With newer versions you can do:
parallel  doit {1} {2} {1/.}{2/.}.out ::: ../mo/?*e.log :::+ ../excited/?*d.log

# If you do not like the {/.} you can do:
parallel doit {1} '{= s/e.log/d.log/;s:/mo/:/excited/:; =}' '{=s/.log/.out/;s:^../mo/::;=}' ::: ../mo/?*e.log

# If all the files do not fit on the command line (because you have thousands):
finda() { find ../mo/ -name '*e.log'; }
findb() { find ../excited/ -name '*d.log'; }

parallel --xapply doit {1} {2} {1/.}{2/.}.out :::: <(finda) <(findb)
parallel doit {1} {2} {1/.}{2/.}.out :::: <(finda) ::::+ <(findb)
finda | parallel doit {1} '{= s/e.log/d.log/;s:/mo/:/excited/:; =}' '{=s/.log/.out/;s:^../mo/::;=}'

Ele executará um trabalho por núcleo. Se você preferir um trabalho de cada vez, substitua parallel por parallel -j1 .

O GNU Parallel é um paralelizador geral e facilita a execução de trabalhos em paralelo na mesma máquina ou em várias máquinas para as quais você tem acesso ssh. Muitas vezes, pode substituir um loop for .

Se você tem 32 tarefas diferentes que você quer rodar em 4 CPUs, uma forma direta de paralelizar é rodar 8 tarefas em cada processador:

O

GNUParallelgeraumnovoprocessoquandoumtermina-mantendoasCPUsativaseeconomizandotempo:

Instalação

Se o GNU Parallel não for empacotado para sua distribuição, você poderá fazer uma instalação pessoal, que não requer acesso root. Isso pode ser feito em 10 segundos ao fazer isso:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

Para outras opções de instalação, consulte o link

Saiba mais

Veja mais exemplos: link

Assista aos vídeos de introdução: link

Percorra o tutorial: link

Inscreva-se na lista de e-mail para obter suporte: link

    
por 10.06.2016 / 19:54