O bash suporta bifurcação semelhante ao fork de C ()?


25

Eu tenho um script que gostaria de bifurcar em um ponto para que duas cópias do mesmo script estejam em execução.

Por exemplo, eu gostaria que o seguinte script bash existisse:

echo $$
do_fork()
echo $$

Se esse script bash realmente existisse, a saída esperada seria:

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

ou

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

Existe algo que eu possa colocar no lugar de "do_fork ()" para obter esse tipo de saída ou fazer com que o script bash execute um fork do tipo C?

Respostas:


23

Sim. A bifurcação é soletrada &:

echo child & echo parent

O que pode confundir você é que $$não é o PID do processo de shell, é o PID do processo de shell original . O objetivo de fazê-lo dessa maneira é que $$é um identificador exclusivo para uma instância específica do shell script: ele não muda durante a execução do script e é diferente de $$qualquer outro script em execução simultaneamente. Uma maneira de obter o PID real do processo de shell é sh -c 'echo $PPID'.

O fluxo de controle no shell não é o mesmo que C. Se em C você escreveria

first(); fork(); second(); third();

então um equivalente shell é

after_fork () { second; third; }
first; after_fork & after_fork

O formato simples do shell first; child & parentcorresponde ao idioma C usual

first(); if (fork()) parent(); else child();

&e $$existe e se comporta dessa maneira em todos os shell do estilo Bourne e no (t) csh. $PPIDnão existia no shell Bourne original, mas está no POSIX (portanto, está no ash, bash, ksh, zsh,…).


3
Mas isso é basicamente "fork + exec", não apenas fork.
mattdm

@mattdm: Uh? &é fork, não há nenhum executivo envolvido. Fork + exec é quando você inicia um comando externo.
Gilles 'SO- stop be evil'

@mattdm: Ah, acho que vejo o que Cory está fazendo. Não há exec, mas os dois idiomas têm um fluxo de controle diferente.
Gilles 'SO- stop be evil'

1
@ Gilles: O operador de controle do bash &inicia um subshell no qual o comando fornecido é executado. Fork + exec. Você não pode simplesmente colocar &sem nenhum comando anterior para executar.
mattdm

5
Bem, se "Forking é soletrado" e "eram uma afirmação verdadeira, você poderia colocar &uma linha sozinha. Mas você não pode. Isso não significa "garfo aqui". Significa "executar o comando anterior em segundo plano em um subshell".
mattdm

10

Sim, isso se chama subshells . O código do shell entre parênteses é executado como um subshell (fork). No entanto, o primeiro shell normalmente espera que a criança seja concluída. Você pode torná-lo assíncrono usando o &terminador. Veja-o em ação com algo como isto:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh


5
Os parênteses criam um subshell, mas isso é fork + wait. &é o garfo sozinho. Se você deseja executar mais de um pipeline no processo filho, basta usar chaves (que executam agrupamentos sem criar um processo filho):{ sleep 2; echo child; } &
Gilles 'SO- stop be evil'

6

Não há nenhuma maneira nativa de bash (ou, pelo que sei, qualquer outra forma típica de * nix shell) de fazer isso. Existem várias maneiras de gerar processos bifurcados que fazem outra coisa de forma assíncrona, mas acho que não há nada que siga a semântica exata da chamada do sistema fork ().

A abordagem típica seria fazer com que seu script de nível superior gerasse ajudantes que fazem exatamente o trabalho que você deseja dividir. Se você faz $0 $@ &ou o que quer, você começará do início novamente e precisará descobrir isso de alguma forma.

Na verdade, estou começando a pensar em várias maneiras inteligentes de se fazer exatamente isso ...

Mas , antes que meu cérebro se empolgue demais com isso, acho que uma regra muito boa é: se você está tentando escrever algo com casca e está ficando cheio de truques inteligentes e deseja mais recursos de linguagem, é hora de mudar para uma linguagem de programação real .


2
Embora seu argumento seja bem aceito, a sintaxe do bash é discutivelmente difícil e faltam as estruturas e os recursos de dados mais elegantes do Perl ou Python, mas o bash é o mais real possível em seu domínio . É uma linguagem específica do domínio, e eu argumentaria ainda melhor (mais sucinto, mais simples) do que, por exemplo, o Python em muitos casos. Você pode administrar uma sala cheia de sistemas e não conhece Python? Sim. Você pode fazer isso e não conhecer um pouco de programação [bash]? Eu não gostaria de tentar. Após 30 anos de programação shell, digo que é o mais real possível. E sim, eu falo Python. Mas não confunda os jovens.
Mike S

2
Dito isto, tecnicamente eu gosto mais desta resposta. Dizer que "&" é a resposta para a pergunta do usuário "bifurca-se a certa altura para que duas cópias do mesmo script estejam em execução" é, na minha opinião, confuso. O que "&" faz, de acordo com o manual do bash, é "... executa o comando [dado] em segundo plano em um subshell". Ele deve finalizar um comando e envolve uma bifurcação (tecnicamente, no Linux, um clone ()), mas nesse ponto duas cópias do mesmo script não estão em execução.
Mike S
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.