¿Bash admite bifurcación similar a la bifurcación de C ()?

25

Tengo un script que me gustaría bifurcar en un punto, por lo que se ejecutan dos copias del mismo script.

Por ejemplo, me gustaría que exista el siguiente script bash:

echo $$
do_fork()
echo $$

Si este script bash realmente existiera, el resultado esperado sería:

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

o

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

¿Hay algo que pueda poner en lugar de "do_fork ()" para obtener este tipo de salida o para hacer que el script bash haga una bifurcación tipo C?

Cory Klein
fuente

Respuestas:

23

Sí. La bifurcación se deletrea &:

echo child & echo parent

Lo que puede confundirte es que $$no es el PID del proceso de shell, es el PID del proceso de shell original . El punto de hacerlo de esta manera es que $$es un identificador único para una instancia particular del script de shell: no cambia durante la ejecución del script, y es diferente de $$cualquier otro script que se ejecute simultáneamente. Una forma de obtener el PID real del proceso de shell es sh -c 'echo $PPID'.

El flujo de control en el shell no es el mismo que C. Si en C escribirías

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

entonces un equivalente de shell es

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

La forma de shell simple first; child & parentcorresponde al idioma habitual de C

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

&y $$existe y se comporta de esta manera en cada shell de estilo Bourne y en (t) csh. $PPIDno existía en el shell Bourne original pero está en POSIX (por lo que está en ash, bash, ksh, zsh, ...).

Gilles 'SO- deja de ser malvado'
fuente
3
Pero eso es básicamente "fork + exec", no solo fork.
mattdm
@mattdm: ¿Uh? &es tenedor, no hay ejecutivo involucrado. Fork + exec es cuando ejecutas un comando externo.
Gilles 'SO- deja de ser malvado'
@mattdm: Ah, creo que veo a qué se dirige Cory. No hay exec, pero los dos idiomas tienen un flujo de control diferente.
Gilles 'SO- deja de ser malvado'
1
@Gilles: el operador de control de bash &inicia una subshell en la que se ejecuta el comando dado. Tenedor + ejecutivo. No puede simplemente poner &sin comando anterior para ejecutar.
mattdm
55
Bueno, si "Bifurcación se deletrea" y fuera una declaración verdadera, podría poner &una línea por sí mismo. Pero no puedes. No significa "tenedor aquí". Significa "ejecutar el comando anterior en segundo plano en una subshell".
mattdm
10

Sí, se llama subshells . El código de shell dentro del paréntesis se ejecuta como un subshell (fork). Sin embargo, el primer caparazón normalmente espera a que se complete el niño. Puede hacerlo asíncrono usando el &terminador. Véalo en acción con algo como esto:

#!/bin/bash

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

$ bash subsh.sh

Keith
fuente
55
Los paréntesis crean una subshell, pero eso es fork + wait. &es tenedor solo. Si desea ejecutar más de una tubería en el proceso secundario, es suficiente usar llaves (que realizan la agrupación sin crear un proceso secundario):{ sleep 2; echo child; } &
Gilles 'SO- deja de ser malvado'
6

No hay una forma nativa de bash (o, que yo sepa, ninguna otra típica * nix shell) de hacer esto. Hay muchas maneras de generar procesos bifurcados que hacen algo más de forma asincrónica, pero no creo que haya nada que siga la semántica exacta de la llamada al sistema fork ().

El enfoque típico sería hacer que su script de nivel superior genere ayudantes que hacen el trabajo que desea dividir. Si lo haces $0 $@ &o lo que sea, comenzarás de nuevo desde el principio y tendrás que resolverlo de alguna manera.

De hecho, estoy empezando a pensar en varias formas inteligentes en las que uno podría hacer exactamente eso ...

Pero , antes de que mi cerebro se deje llevar por eso, creo que una regla bastante buena es: si estás tratando de escribir algo en shell y se está llenando de trucos ingeniosos y deseas más funciones de lenguaje, tiempo para cambiar a un lenguaje de programación real .

mattdm
fuente
2
Aunque su punto está bien tomado: la sintaxis de bash es posiblemente difícil y le faltan las estructuras de datos y características más elegantes de Perl o Python, bash es tan real como es posible en su dominio . Es un lenguaje de dominio específico, y yo diría que incluso mejor (más sucinto, más simple) que, por ejemplo, Python en muchos casos. ¿Puedes administrar una sala llena de sistemas y no conocer Python? Sí. ¿Puedes hacer eso y no saber ni una pizca de bash [programación]? No me gustaría intentarlo. Después de 30 años de programación de shell, te digo que es tan real como parece. Y sí, hablo Python. Pero no confunda a los jóvenes.
Mike S
2
Dicho esto, técnicamente me gusta más esta respuesta. Decir que "&" es la respuesta a la pregunta del usuario, "bifurcar en un punto para que se ejecuten dos copias del mismo script" es confuso. Lo que hace "&", según el manual de bash, es "... ejecuta el comando [dado] en segundo plano en una subshell". Debe terminar un comando, y sí implica una bifurcación (técnicamente, en Linux, un clon ()), pero en ese momento no se ejecutan dos copias del mismo script.
Mike S