Como o bash trata “()”

8

Enquanto fazia experimentos com redirecionamento de saída e substituição de processo, deparei com o seguinte comando e sua saída resultante:

    me@elem:~$ echo foo > >(cat); echo bar
    bar
    me@elem:~$ foo

(Sim, essa nova linha vazia no final é intencional.)

Então a barra do bash echo, imprime meu prompt usual, echo's foo, echo é uma nova linha e deixa meu cursor lá. Se eu apertar enter novamente, ele imprimirá o meu prompt em uma nova linha e deixará o cursor seguindo-a (como esperado quando alguém clicar em uma linha de comando vazia).

Eu esperava que ele escrevesse foo para um descritor de arquivo, cat o leu e o eco foo, a barra do segundo eco echo e, em seguida, de volta ao prompt de comando. Mas esse não é claramente o caso.

Alguém poderia explicar o que está acontecendo?

    
por Stanley Yu 17.03.2015 / 21:30

2 respostas

7

Você pode ver foo exibido antes de bar , depois de bar ou mesmo após o aviso, dependendo do tempo. Adicione um pequeno atraso para obter tempo consistente:

$ echo foo > >(sleep 1; cat); echo bar; sleep 2 
bar
foo
$

bar aparece imediatamente, depois foo após um segundo e, em seguida, o próximo prompt após outro segundo.

O que está acontecendo é que o bash executa as substituições do processo em segundo plano.

  1. O processo bash principal inicia um subshell para executar sleep 1; cat e configura um canal para ele.
  2. O processo bash principal executa echo foo . Como isso não preenche o buffer do pipe, o comando echo termina sem bloquear.
  3. O processo bash principal executa echo bar .
  4. O processo bash principal inicia o comando sleep 2 .
  5. Enquanto isso, o subshell está iniciando o comando sleep 1 .
  6. Após cerca de 1 segundo, sleep 1 retorna no subprocesso. O subprocesso continua a executar cat .
  7. cat copia sua entrada para sua saída (que é exibida na tela) e retorna.
  8. O subshell terminou seu trabalho, sai.
  9. Depois de outro segundo, sleep 2 retorna. O processo principal do shell termina a execução e você pode ver o próximo prompt.
por 18.03.2015 / 02:12
3

Você não precisa de substituição de processo para obter esse efeito. Tente isto:

( echo foo | cat & )

Você obterá o mesmo resultado (sem o bar ; deixarei isso como um exercício) e pelo mesmo motivo. Nos dois casos, cat é iniciado como uma tarefa em segundo plano. Na minha linha aqui, isso é explícito. No caso de substituição de processos, também é explícito - é um processo separado anexado a um descritor de arquivo de nomes - mas talvez não seja tão óbvio.

O processo filho não termina necessariamente antes de bash imprimir o próximo prompt. E como sua saída é armazenada em buffer, ela não produz nada até que seja finalizada. Nesse ponto, o bash acabou de imprimir $ no stderr, e agora o processo de segundo plano sai depois de imprimir foo e uma nova linha.

    
por 17.03.2015 / 21:47