wait falha no comando

3

O script abaixo não tem outro propósito além de ilustrar essa questão.

#!/usr/bin/env zsh

arbitrary_pipeline () {
    shuf | tr a-z A-Z
}

tmpdir=$( mktemp -d )

mkfifo $tmpdir/{orig,alt}

{ tee $tmpdir/orig | arbitrary_pipeline > $tmpdir/alt; } &
pid=$!

paste $tmpdir/orig $tmpdir/alt

rm -rf $tmpdir

wait $pid

O script usa tee e dois pipes nomeados para dividir alguma entrada padrão (arbitrária) em dois fluxos, redireciona um deles para um pipeline arbitrário e transmite os dois fluxos resultantes às entradas para paste . Esquematicamente:

STDIN --- > --.- arbitrary_pipeline -.
               \                      \
          paste '----<FIRST-ARGUMENT>  '- <SECOND-ARGUMENT> --> STDOUT

(Nesse caso, arbitrary_pipeline apenas embaralha seu stdin e o converte em maiúsculas, mas, como o nome sugere, pode ser qualquer coisa.)

A saída stdout do script parece boa, mas o comando wait sempre falha:

% grep -iP 'z.*s.*h' /usr/share/dict/words | /tmp/test.sh
Nietzsche   CITIZENSHIP'S
Zubeneschamali  NIETZSCHE
Zubeneschamali's    ZUBENESCHAMALI
citizenship CITIZENSHIP
citizenship's   ZUBENESCHAMALI'S
/tmp/test.sh:wait:18: pid 26357 is not a child of this shell

O que estou fazendo de errado?

FWIW:

/usr/bin/env zsh --version
# zsh 5.0.7 (x86_64-pc-linux-gnu)

EDITOS:

  1. adicionaram chaves ao redor do tee pipeline, por jordanm sugestão. (Resultados não mudaram, no entanto.)
  2. substituiu &! por & em resposta ao comentário de Stéphane Chazelas. (Novamente, os resultados não mudaram.)
por kjo 04.11.2016 / 21:01

1 resposta

3

Antes de 5.0.8, zsh não podia esperar por trabalhos já mortos. Isso foi alterado em 5.0.8 em 2014. Veja a alteração existente .

Aqui, você pode apenas redirecionar o stderr para /dev/null para ignorar o problema:

wait $pid 2> /dev/null

Observe que em:

{ tee $tmpdir/orig | arbitrary_pipeline > $tmpdir/alt; } &

como uma otimização, zsh não irá bifurcar um processo extra para arbitrary_pipeline , ele irá executá-lo no mesmo processo que aquele que executa essa sub-inicial em segundo plano.

paste não terminará antes de ver EOF em seu stdin, sendo seu stdin o canal em que $pid (e seus filhos, se algum) está escrevendo no outro extremo. Portanto, ele não verá eof até que $pid (e filhos) tenha fechado todos os descritores de arquivo (geralmente apenas stdout) na extremidade de gravação do canal. A menos que $pid feche explicitamente seu stdout (o que é muito incomum), isso só acontecerá quando sair.

O que isso significa é que paste , na maioria dos casos, não sairá antes de $pid , ainda é uma boa ideia fazer o wait apenas no caso.

Note que aqui você pode usar um coproc para evitar os fifos temporários:

coproc arbitrary_pipeline
cat >&p | paste - /dev/fd/3 3<&p &
coproc : close
wait

(observe que wait também aguarda o coproc s).

    
por 05.11.2016 / 12:37