Processos em background misturam ordem de execução de script de shell

1

Alguém pode me explicar por que o script

echo one && 
echo two & 
echo three && 
echo four

me dá

[1] 3692
three
four
one
two
[1]+  Done                    echo one && echo two

Aparentemente, tudo o que está por trás do processo de segundo plano é exibido primeiro e as linhas de código cronologicamente antes do processo em segundo plano são impressas por último. Eu tropecei em um roteiro que tentei escrever e não entendo por que ele se comporta assim (embora eu ache que existe alguma engenhosidade por trás disso).

Eu já descobri que posso evitar isso com colchetes:

echo one && 
(echo two &) 
echo three && 
echo four

one
two
three
four

e

echo one && 
(sleep 2 && echo two &)
echo three && 
echo four

one
three
four
two

Porque a linha dois dorme em segundo plano e, portanto, sai quando as primeiras linhas já foram executadas.

Mas por que os colchetes têm esse efeito?

Pergunta bônus: Por que os colchetes impedem a saída do PID de plano de fundo?

    
por nnn 10.04.2015 / 00:16

2 respostas

1

echo one && 
echo two & 
echo three && 
echo four

Tenha em mente que isso é analisado como

echo one && echo two &
echo three && echo four

Assumirei que os comandos echo foram bem-sucedidos (eles só falhariam em casos de borda, como o redirecionamento para um arquivo em um disco cheio). Portanto, esse snippet executa duas tarefas em paralelo: uma imprime as linhas one e two e a outra imprime as linhas three e four . A intercalação de one e two com three e four não é garantida e provavelmente varia de sistema para sistema, de shell para shell e de invocação para invocação. Para um exemplo de brinquedo como esse, você pode observar resultados reproduzíveis em um sistema pouco carregado, mas isso não é algo com o qual você possa contar.

echo one && 
(echo two &) 
echo three && 
echo four

Você alterou a análise: aqui apenas o comando echo two é executado em segundo plano. Isso garante que one seja exibido primeiro e, como antes, three sempre estará antes de four , mas o posicionamento de two poderia estar em qualquer lugar após one .

O shell só imprime uma mensagem sobre os processos em segundo plano, se eles forem iniciados a partir do processo principal do shell, e não quando forem iniciados em um subshell. Parênteses criam um subshell, e é por isso que (echo two &) não faz com que o shell imprima qualquer mensagem. Isso cria um processo em segundo plano, mas não um trabalho trabalho .

echo one && 
(sleep 2 && echo two &)
echo three && 
echo four

Nesse snippet, o trabalho em segundo plano fica suspenso por 2 segundos antes de exibir two . Isso torna extremamente provável (mas não realmente garantida) que two será produzido após three e four .

    
por 10.04.2015 / 02:01
1

Parte 1

echo one && 
echo two & 
echo three && 
echo four

Isso pode ser reescrito como

echo one && echo two & 
echo three && echo four

O motivo pelo qual você obtém o three e o four primeiro é simplesmente que leva mais tempo para que a subshell manipule o one e o two em execução, do que para imprimir o three e four .

Você pode ver isso um pouco mais claramente como este

echo one && echo two &
sleep 1
echo three && echo four

Nesta situação, você obtém one e two , seguido um segundo depois por three e four .

Observe que, no cenário original, não há garantia de que one e two não serão misturados com a saída de three e four , possivelmente com palavras interpoladas, como thonreee ou twfouro .

Parte 2

echo one && 
(echo two &) 
echo three && 
echo four

Isso pode ser reescrito como

echo one && (echo two &) 
echo three && echo four

Aqui, o que está acontecendo é que one é impresso imediatamente e, em seguida, o two é disparado em uma subcamada. Em seguida, (em série) a próxima linha é executada, resultando em three e four . Em sua situação específica, a subpaina é pequena e rápida o suficiente para que o two possa ser impresso antes da saída three . Nenhuma garantia disso, no entanto, também.

Parte 3

Os parênteses agrupam as instruções em uma subcamada. O e comercial & se aplica a uma instrução, mas, neste caso, você usou && para vincular os dois comandos e, portanto, eles devem ser tratados como uma única instrução.

Talvez você deva usar echo one; echo two em vez de echo one && echo two ? Eles são muito diferentes. O ponto-e-vírgula ; separa dois comandos, que são executados de forma independente, mas sequencialmente. O duplo e comercial && une os dois comandos como um AND lógico , de modo que o segundo só será executado se o primeiro for concluído com êxito. Compare false; echo yes , false && echo yes e true && echo yes . Em seguida, experimente substituindo && ( lógico AND ) por || ( OR lógico ).

Bônus

Você perde a notificação de controle de trabalho porque o subshell não tem controle de trabalho.

    
por 10.04.2015 / 01:52