Nawiasy zawsze rozpoczynają podpowłokę. Dzieje się tak, że bash wykrywa, że sleep 5
jest to ostatnie polecenie wykonane przez tę podpowłokę, więc wywołuje exec
zamiast fork
+ exec
. sleep
Komenda zastępuje powłoki w tle w tym samym procesie.
Innymi słowy, podstawowym przypadkiem jest:
( … )
utwórz podpowłokę. Oryginalne wywołania procesów fork
i wait
. W podprocesie, który jest podpowłoką:
sleep
jest zewnętrznym poleceniem, które wymaga podprocesu podprocesu. Wywołania podpowłoki fork
i wait
. W podprocesie:
- Podproces wykonuje polecenie zewnętrzne →
exec
.
- Ostatecznie polecenie kończy się →
exit
.
wait
uzupełnia się w podpowłoce.
wait
kończy się w oryginalnym procesie.
Optymalizacja to:
( … )
utwórz podpowłokę. Oryginalne wywołania procesów fork
i wait
. W podprocesie, który jest podpowłoką, dopóki nie wywoła exec
:
sleep
jest poleceniem zewnętrznym i jest ostatnią rzeczą, którą ten proces musi zrobić.
- Podproces wykonuje polecenie zewnętrzne →
exec
.
- Ostatecznie polecenie kończy się →
exit
.
wait
kończy się w oryginalnym procesie.
Po dodaniu czegoś innego po wywołaniu sleep
należy zachować podpowłokę, aby ta optymalizacja nie mogła się zdarzyć.
Kiedy dodasz coś jeszcze przed wywołaniem sleep
, można dokonać optymalizacji (i robi to ksh), ale bash tego nie robi (przy tej optymalizacji jest bardzo konserwatywny).
Gilles „SO- przestań być zły”
źródło
fork
a proces potomny jest tworzony (w celu wykonywania poleceń zewnętrznych) przez wywołaniefork + exec
. Ale twój pierwszy para sugeruje, żefork + exec
jest to również wymagane dla podpowłoki. Co się tutaj mylę?fork
+exec
nie jest wywoływany dla podpowłoki, jest wywoływany dla polecenia zewnętrznego. Bez jakiejkolwiek optymalizacji istniejefork
wywołanie podpowłoki i kolejne polecenie zewnętrzne. Do mojej odpowiedzi dodałem szczegółowy opis przepływu.(...)
(w przypadku podstawowym) może istnieć wywołanieexec
zależne od tego, czy podpowłoka ma jakieś zewnętrzne polecenie do wykonania, podczas gdy w przypadku wykonania jakiegokolwiek zewnętrznego polecenia musi byćfork + exec
.date
w powłoce?strace -f -e clone,execve,write bash -c 'date'
istrace -f -e clone,execve,write bash -c 'date; true'
Z Przewodnika programowania zaawansowanego Bash :
„Ogólnie rzecz biorąc, zewnętrzne polecenie w skrypcie odrzuca podproces, podczas gdy wbudowane Bash nie. Z tego powodu wbudowane polecenia wykonują się szybciej i zużywają mniej zasobów systemowych niż ich zewnętrzne odpowiedniki”.
I nieco dalej:
„Lista poleceń osadzona między nawiasami działa jako podpowłoka”.
Przykłady:
Przykład użycia kodu OPs (z krótszymi snami, ponieważ jestem niecierpliwy):
Wyjście:
źródło
sleep
będzie działała w podpowłoce (być może w procesie podpowłoki, ponieważ jest to wbudowana, a nie podproces podpowłoki). W każdym razie spodziewałbym się, że istnieje podpowłoka, tj. Podproces Bash w ramach nadrzędnego procesu Bash. W przypadku powyższego fragmentu B wydaje się, że tak nie jest.sleep
nie wydaje się być wbudowanym, oczekiwałbym, że drugiesleep
wywołanie w obu fragmentach będzie działało w podprocesie procesu podpowłoki.$BASHPID
zmiennej. Niestety sposób, w jaki to robiłeś, nie dawał ci całej historii, w którą wierzę. Zobacz moje dodane wyniki w odpowiedzi.Dodatkowa uwaga do odpowiedzi @Gilles.
Jak powiedział Gilles:
The parentheses always start a subshell.
Jednak liczby, które ma taka podpowłoka, mogą się powtarzać:
Jak widać, $$ ciągle się powtarza, i to zgodnie z oczekiwaniami, ponieważ (wykonaj to polecenie, aby znaleźć poprawną
man bash
linię):To znaczy: Jeśli powłoka nie zostanie ponownie zainicjowana, $$ jest taka sama.
Lub z tym:
Jest
$$
to identyfikator bieżącej powłoki (nie podpowłoki).źródło