Czy bash obsługuje rozwidlenie podobne do C's fork ()?

25

Mam skrypt, który chciałbym rozwidlić w pewnym momencie, więc działają dwie kopie tego samego skryptu.

Na przykład chciałbym, aby istniał następujący skrypt bash:

echo $$
do_fork()
echo $$

Jeśli ten skrypt bash naprawdę istniał, oczekiwanym wynikiem byłoby:

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

lub

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

Czy jest coś, co mogę umieścić zamiast „do_fork ()”, aby uzyskać tego rodzaju dane wyjściowe lub spowodować, że skrypt bash wykona rozwidlenie podobne do C?

Cory Klein
źródło

Odpowiedzi:

23

Tak. Rozwidlenie jest pisane &:

echo child & echo parent

Co może być mylące, ponieważ $$nie jest to PID procesu powłoki, to PID oryginalnego procesu powłoki. Chodzi o to, aby $$był to unikalny identyfikator dla konkretnej instancji skryptu powłoki: nie zmienia się podczas wykonywania skryptu i jest inny niż $$w żadnym innym równolegle działającym skrypcie. Jednym ze sposobów uzyskania rzeczywistego PID procesu powłoki jest sh -c 'echo $PPID'.

Przepływ kontrolny w powłoce nie jest taki sam jak C. Jeśli piszesz w C.

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

wtedy odpowiednikiem powłoki jest

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

Prosta forma powłoki first; child & parentodpowiada zwykłemu idiomowi C.

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

&i $$istnieją i zachowują się w ten sposób w każdej powłoce w stylu Bourne'a oraz w (t) csh. $PPIDnie istniał w oryginalnej powłoce Bourne'a, ale jest w POSIX (więc jest w ash, bash, ksh, zsh,…).

Gilles „SO- przestań być zły”
źródło
3
Ale to w zasadzie „fork + exec”, nie tylko fork.
mattdm
@mattdm: Uh? &jest widelec, nie jest zaangażowany żaden exec. Fork + exec ma miejsce po uruchomieniu zewnętrznego polecenia.
Gilles „SO- przestań być zły”
@mattdm: Ach, chyba rozumiem, do czego zmierza Cory. Nie ma exec, ale oba języki mają różny przebieg sterowania.
Gilles „SO- przestań być zły”
1
@Gilles: Operator kontroli bash &uruchamia podpowłokę, w której wykonywane jest dane polecenie. Widelec + exec. Nie można po prostu wstawić &bez poprzedniego polecenia do wykonania.
mattdm,
5
Cóż, jeśli „Forking is orced &” były prawdziwym stwierdzeniem, możesz postawić &linię samą w sobie. Ale nie możesz. Nie oznacza to „rozwidlenia tutaj”. Oznacza to „wykonaj poprzednie polecenie w tle w podpowłoce”.
mattdm
10

Tak, to się nazywa podpowłoki . Kod powłoki w nawiasie jest uruchamiany jako podpowłoka (rozwidlenie). Jednak pierwsza skorupa zwykle czeka na ukończenie przez dziecko. Możesz ustawić go jako asynchroniczny za pomocą &terminatora. Zobacz to w akcji z czymś takim:

#!/bin/bash

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

$ bash subsh.sh

Keith
źródło
5
Nawiasy tworzą podpowłokę, ale to rozwidlenie + czekanie. &jest sam widelec. Jeśli chcesz wykonać więcej niż jeden potok w procesie potomnym, wystarczy użyć nawiasów klamrowych (które wykonują grupowanie bez tworzenia procesu potomnego):{ sleep 2; echo child; } &
Gilles 'SO - przestań być zły'
6

Nie ma natywnego basha (lub, o ile mi wiadomo, jakiejkolwiek innej typowej powłoki * nix). Istnieje wiele sposobów na odradzanie rozwidlonych procesów, które wykonują coś innego asynchronicznie, ale nie sądzę, że istnieje coś, co podąża dokładnie za semantyką wywołania systemowego fork ().

Typowe podejście polega na tym, że skrypt najwyższego poziomu odradza pomocników wykonujących tylko tę pracę, którą chcesz rozdzielić. Jeśli to zrobisz, $0 $@ &cokolwiek, zaczniesz od początku i musisz to jakoś wymyślić.

Właściwie zaczynam myśleć o kilku sprytnych sposobach, w jakie można to zrobić ...

Ale zanim mój mózg zostanie tym zbyt pochłonięty, myślę, że całkiem dobrą zasadą jest: jeśli próbujesz napisać coś w skorupce i zapełni się on sprytnymi sztuczkami i pragniesz więcej funkcji językowych, czas na zmianę do prawdziwego języka programowania .

mattdm
źródło
2
Mimo, że masz rację - składnia bash jest prawdopodobnie trudna i brakuje w niej bardziej eleganckich struktur danych i funkcji Perla lub Pythona, bash jest tak realny, jak to możliwe - w swojej domenie . Jest to język specyficzny dla domeny i argumentowałbym nawet lepiej (bardziej zwięzłe, prostsze) niż np. Python w wielu przypadkach. Czy możesz zarządzać wieloma systemami i nie znasz Pythona? Tak. Czy potrafisz to zrobić i nie znasz bashu [programowania]? Nie chciałbym próbować. Po 30 latach programowania powłoki powiem ci, że jest tak realne, jak to tylko możliwe. I tak, mówię w języku Python. Ale nie myl młodzieży.
Mike S
2
To powiedziawszy, technicznie bardziej podoba mi się ta odpowiedź. Powiedzieć, że „&” jest odpowiedzią na pytanie użytkownika, „rozwidlenie w pewnym momencie, tak że działają dwie kopie tego samego skryptu”, jest dla mnie mylące. Zgodnie z instrukcją bash „&” wykonuje „... wykonuje polecenie [podane] w tle w podpowłoce”. Musi zakończyć polecenie i wymaga rozwidlenia (technicznie w Linuksie klon ()), ale w tym momencie dwie kopie tego samego skryptu nie są uruchomione.
Mike S,