Como executar processos paralelos e combinar saídas quando ambos terminaram

13

Eu tenho um script de shell bash em que canalizo alguns dados através de cerca de 5 ou 6 programas diferentes, em seguida, os resultados finais em um arquivo delimitado por tabulação.

Eu então faço o mesmo novamente para um conjunto de dados similar separado e envio para um segundo arquivo.

Em seguida, os dois arquivos são inseridos em outro programa para análise comparativa. por exemplo. para simplificar

Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv
AnalysisProg -i Data1res.csv Data2res.csv

Minha pergunta é: como posso fazer o step1 e o step2 rodarem ao mesmo tempo (por exemplo, usando &), mas só iniciar o step3 (AnalysisProg) quando ambos estiverem completos?

thx

ps AnalysisProg não funcionará em um fluxo ou fifo.

    
por Stephen Henderson 28.03.2014 / 16:18

4 respostas

24

Use wait . Por exemplo:

Data1 ... > Data1Res.csv &
Data2 ... > Data2Res.csv &
wait
AnalysisProg

irá:

  • execute os canais Data1 e Data2 como trabalhos em segundo plano
  • espere que ambos terminem
  • execute o AnalysisProg.

Veja, por exemplo, esta pergunta .

    
por 28.03.2014 / 16:30
12

A resposta do cxw é sem dúvida a solução preferível, se você tiver apenas 2 arquivos. Se os 2 arquivos são apenas exemplos e você, na realidade, tem 10000 arquivos, então o '&' A solução não funcionará, pois isso sobrecarregará seu servidor. Para isso você precisa de uma ferramenta como o GNU Parallel:

ls Data* | parallel 'cat {} | this | that |theother | grep |sed | awk |whatever > {}res.csv
AnalysisProg -i *res.csv

Para saber mais sobre o GNU Parallel:

  • Assista ao vídeo de introdução para uma introdução rápida: link
  • Percorra o tutorial (man parallel_tutorial). Você linha de comando vou te amar por isso.
por 28.03.2014 / 20:20
1

Uma maneira de fazer isso pode ser algo como:

AnalysisProg <<PREPROCESS /dev/stdin
$( 
{   process1=$( pipe | line | 1 >&2 & echo $! )
    process2=$( pipe | line | 2 >&2 & echo $! )
    while ps -p $process1 $process2 >/dev/null; do
        sleep 1
    done
} 2>&1
)
#END
PREPROCESS

Dessa forma, você faz o background de ambos os pipelines, mas ainda espera que eles terminem a execução antes de combinar sua saída em stdin, que é avaliada em um documento aqui e entregue ao AnalysisProg. Se você puder usar wait , isso é ainda melhor que o loop while ps , mas dependendo do shell, wait pode objetar se você instrui para esperar em um processo que não é filho do shell atual.

Observe também que o método acima irá agrupar a saída - para que ambos os processos sejam gravados de uma só vez. Se você quisesse separá-los ou anexar um ao outro, possivelmente você poderia fazer:

AnalysisProg 3<<PREPROCESS /dev/fd/3 /dev/stderr
$(
process1=$(... >&2 ...) 2>/dev/fd/3
...
} 3>/dev/fd/3 2>/dev/stderr
)

Eu já demonstrei esses conceitos antes. Provavelmente, as melhores demonstrações são aqui e aqui .

    
por 29.03.2014 / 12:59
0

Tente usar isso.

rm -f Data1Res.csv
rm -f Data2Res.csv
Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv &
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv &
while true
do
  ps aux | grep -v grep | grep -i -E 'Data1Res.csv|Data2Res.csv' &> /dev/null
  if [ $? -ne 0 ]
  then
    AnalysisProg -i Data1res.csv Data2res.csv
    exit 0
  fi
done
    
por 28.03.2014 / 16:35