W tym konkretnym przypadku masz exec
w potoku. Aby wykonać serię poleceń potokowych, powłoka musi początkowo rozwidlić się, tworząc podrzędną powłokę. (W szczególności musi utworzyć rurę, a następnie widelec, aby wszystko przebiegło "po lewej stronie" rury, może mieć wyjście wysyłane do tego, co znajduje się "po prawej stronie" rury.)
Aby zobaczyć, że to w rzeczywistości jest to, co się dzieje, porównaj:
{ ls; echo this too; } | cat
z:
{ exec ls; echo this too; } | cat
dawnej trasy ls
bez wychodzenia z sub-shell, tak że ten sub-shell jest zatem nadal wokół uruchomić echo
. Ta ostatnia działa pod numerem ls
, opuszczając pod-powłokę, co powoduje, że nie jest już dostępna do wykonania echo
, a this too
nie jest drukowana.
(wykorzystanie kręcone szelki { cmd1; cmd2; }
normalnie hamuje widelca działań sub-otoczka, które można otrzymać z nawiasami (cmd1; cmd2)
, ale w tym przypadku rury, widelec „na siłę”, jak to było).
Przekierowanie aktualnej powłoki dzieje się tylko wtedy, gdy po słowie exec
nie ma "nic do uruchomienia". Zatem np. exec >stdout 4<input 5>>append
modyfikuje bieżącą powłokę, ale exec foo >stdout 4<input 5>>append
próbuje wykonać komendę exec foo
. [Uwaga: nie jest to ściśle dokładne; patrz załącznik.]
Co ciekawe, w interaktywnej powłoki, po exec foo >output
powiodło się, ponieważ nie ma polecenia foo
, kije powłoki wokół, ale pozostaje stdout przekierowanie do pliku output
. (Można odzyskać z exec >/dev/tty
W skrypcie, brak exec foo
kończy skrypt.).
Z wierzchołka kapelusza @ Pumbaa80, oto coś bardziej obrazowe:
#! /bin/bash
shopt -s execfail
exec ls | cat -E
echo this goes to stdout
echo this goes to stderr 1>&2
(uwaga: cat -E
jest uproszczony w porównaniu z moim zwykłym cat -vET
, co jest moim przydatnym poleceniem "pokaż mi niedrukowalne znaki w rozpoznawalny sposób"). Kiedy ten skrypt jest uruchamiany, dane wyjściowe z ls
mają zastosowanie cat -E
(w Linuksie powoduje to, że koniec linii jest widoczny jako znak $), ale dane wyjściowe wysyłane na stdout i stderr (w pozostałych dwóch wierszach) to , a nie przekierowanie . Zmień | cat -E
na > out
i po uruchomieniu skryptu obserwuj zawartość pliku out
: nie ma tam dwóch ostatnich echo
s.
Teraz zmień ls
na foo
(lub inne polecenie, które nie zostanie znalezione) i ponownie uruchom skrypt. Tym razem wynik jest:
$ ./demo.sh
./demo.sh: line 3: exec: foo: not found
this goes to stderr
a plik out
ma teraz zawartość produkowanych przez pierwszy echo
linii.
To czyni to, co exec
"naprawdę robi" tak oczywiste, jak to możliwe (ale nie bardziej oczywiste, jak Albert Einstein nie powiedział :-)).
Normalnie, gdy powłoka przechodzi do wykonania "prostego polecenia" (patrz strona manuala dla dokładnej definicji, ale to w szczególności wyklucza polecenia w "potoku"), przygotowuje wszelkie operacje przekierowania we/wy określone przez <
, >
itd., Otwierając potrzebne pliki. Następnie powłoka wywołuje fork
(lub inny równoważny, ale bardziej wydajny wariant, taki jak vfork
lub clone
zależnie od systemu operacyjnego, konfiguracji itp.), Aw procesie potomnym przestawia otwarte deskryptory plików (używając wywołań dup2
lub równoważnych) w celu uzyskania żądane końcowe ustalenia: > out
przemieszcza otwarty deskryptor fd 1-do-stdout podczas 6> out
przesuwa otwarty deskryptor fD 6.
Jeśli podasz exec
kluczowe, choć powłoka hamuje krok fork
. Wykonuje jak zwykle wszystkie operacje otwierania plików i zmiany deskryptorów plików, ale tym razem, wpływa na wszystkie kolejne polecenia:. Na koniec, po wykonaniu wszystkich przekierowań, powłoka próbuje wykonać polecenie (jeśli chodzi o wywołanie systemowe), jeśli taka istnieje.Jeśli nie ma żadnego polecenia lub jeśli połączenie execve()
nie powiedzie się, to powłoka powinna kontynuować działanie (jest interaktywna lub ustawiłeś execfail
), włączono powłokę. Jeśli execve()
powiedzie się, powłoka już nie istnieje, po jej zastąpieniu przez nowe polecenie. Jeśli execfail
zostanie rozbrojony, a powłoka nie będzie interaktywna, powłoka zostanie zamknięta.
(Jest też dodatkowe utrudnienie funkcji command_not_found_handle
powłoki: bash na exec
wydaje się tłumić uruchomienie go, na podstawie wyników badań exec
kluczowe w ogóle sprawia, że powłoka nie patrzeć na swoich funkcji, czyli jeśli masz. shell funkcja f, bieganie f
jako prostego polecenia uruchamia funkcję powłoki, podobnie jak (f)
który prowadzi go w sub-shell, ale działa (exec f)
przeskakuje nad nim).
jak, dlaczego
ls>out1 ls>out2
tworzy dwa pliki (z lub bez
exec
), jest to dość proste: powłoka otwiera każde przekierowanie, a następnie używa
dup2
do przenoszenia deskryptorów plików. Jeśli masz dwa zwykłe przekierowania
>
, powłoka otwiera obie, przenosi pierwszą do fd 1 (stdout), a następnie przenosi drugą do fd 1 (ponownie stdout), zamykając pierwszą w procesie. W końcu działa
ls ls
, ponieważ to pozostało po usunięciu
>out1 >out2
. Tak długo, jak nie ma pliku o nazwie
ls
, polecenie
ls
narzeka na stderr i nie zapisuje niczego na standardowe wyjście.
Nauczyłem się czegoś! – blueshift
Łącze na 'exec' jest funkcją C' exec'. Testowane jest 'bash'' build'. One nie są takie same. Zobacz www.gnu.org/software/bash/manual/bashref.html –
@ J-16SDiZ poprawiono zgodnie z sugestią, ale problem nadal występuje – artaxerxe