2012-03-29 11 views
36

Od Bash Reference Manual uzyskać następujące informacje exec bash wbudowane polecenie:Potrzeba wyjaśnienia Linux bash wbudowanego polecenia exec zachowania

Jeśli dostarcza polecenia, zastępuje powłokę bez tworzenia nowego procesu.

Teraz mam następujące bash skrypt:

#!/bin/bash 
exec ls; 
echo 123; 
exit 0 

Ten wykonany, mam to:

cleanup.sh ex1.bash file.bash file.bash~ output.log 
(files from the current directory) 

Teraz, gdy mam ten skrypt:

#!/bin/bash 
exec ls | cat 
echo 123 
exit 0 

Otrzymuję następujący wynik:

cleanup.sh 
ex1.bash 
file.bash 
file.bash~ 
output.log 
123 

Moje pytanie brzmi:

przypadku gdy exec jest wywoływana zastępuje powłokę bez tworzenia nowego procesu, dlaczego kiedy umieścić | cat The echo 123 jest drukowany, ale bez niej nie ma. Byłbym szczęśliwy, gdyby ktoś mógł wyjaśnić, jaka jest logika tego zachowania.

Dzięki.

EDIT: Po @torek odpowiedzi, mam jeszcze trudniej wytłumaczyć zachowanie:

1. exec ls>out polecenie tworzy plik out i umieścić w nim wynik komenda ls „s;

2. tworzy tylko pliki, ale nie umieszczać w nich żadnych wyników. Jeśli polecenie działa zgodnie z sugestią, myślę, że polecenie numer 2 powinno mieć taki sam wynik, jak polecenie numer 1 (nawet więcej, myślę, że nie powinno było utworzyć pliku out2).

+4

Nauczyłem się czegoś! – blueshift

+1

Łą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 –

+0

@ J-16SDiZ poprawiono zgodnie z sugestią, ale problem nadal występuje – artaxerxe

Odpowiedz

38

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.

+1

Jeśli chodzi o (nie) interaktywną powłokę, strona podręcznika mówi "Jeśli polecenie' nie może być uruchamiany z jakiegoś powodu, nieinteraktywna powłoka wyjściowa, chyba że włączona jest opcja powłoki 'execfail', w którym to przypadku zwraca błąd.Po powrocie powraca interaktywna powłoka" – user123444555621

+0

@torek spójrz na część EDIT w pytaniu – artaxerxe

+0

@ Pumbaa80 : bardzo dobrze; to pomaga uczynić "jak działa exec" jaśniejszym. Dodam notatkę do mojej odpowiedzi. – torek

Powiązane problemy