Script não espera por subprocessos de um loop

3

Em um script bash eu percorro as pastas procurando por alguns arquivos e, se os encontrar, chamo uma função com o diretório que contém esses arquivos. Veja abaixo

pairedread $1 &
pairedread $2 &
pairedread $3 & 
wait
echo "Done ..."

echo 
echo "======================"
echo "Testing again"
echo "======================"
echo

find . -type d -print | while read DIR; do
    echo "reading..."
    test -r "$DIR"/*_1.gz -a -r "$DIR"/*_2.gz || continue
    ( pairedread $DIR &  )
    done

wait
echo "Done..."

pairedread é a função que pega a pasta e chama um script python nos arquivos que estão no diretório especificado. No primeiro caso, ie quando eu explicitamente forneço as pastas que contêm os arquivos de interesse, o script é executado com instâncias de pairedread em execução e, finalmente, terminando, seguido da mensagem útil "Done..." após todos os subprocessos concluídos.

No segundo caso, os mesmos três diretórios são selecionados e três instâncias de paredread são criadas. No entanto, o script não espera nada, ele imprime "Done..." imediatamente e retorna enquanto os subprocessos estão sendo executados em segundo plano.

Estou faltando alguma coisa? Por que não posso esperar que os subprocessos terminem antes de continuar com o script?

    
por posdef 29.03.2016 / 16:43

2 respostas

2

Como você está iniciando esses processos em um subshell (por causa do pipe e por causa das opções (...) extras), o wait não sabe sobre nenhum filho que esperar. Você pode reescrever esse loop para que não exija um subshell como:

while read DIR; do
    echo "reading..."
    test -r "$DIR"/*_1.gz -a -r "$DIR"/*_2.gz || continue
    pairedread $DIR &
done < <(find . -type d -print)

Espere apenas sobre filhos do processo atual. Quando você usa | , cria um subshell para as partes conectarem o stdin / stdout dos lados juntos. Qualquer processo lançado em um subshell não é um filho do processo "top", então wait não sabe sobre eles.

Portanto, neste caso, você foi frustrado ao lançar explicitamente sua pairedread em uma subshell com sintaxe () , e também por ter ocorrido dentro do bloco de um loop while em um pipeline.

Reescrevendo esse bloco para evitar o pipeline e removendo os subshells explícitos permite que o outer wait saiba sobre os processos filhos e faça o que você esperava

    
por 29.03.2016 / 17:31
1

Como @Eric apontou, você precisa de um background fora do pipe e não de subshell o comando, se você quiser esperar pelo processo.

Garfo duplo: quando você faz no mínimo dois garfos, o processo fica órfão e o processo de inicialização se torna o pai do processo.

Seu código: Você fez três forks (pipe, subshell e background), por causa disso, o processo init se torna pai de seu processo recém-iniciado e você não pode esperar, pois wait pode esperar em seu próprio processo filho.

    
por 29.03.2016 / 17:54