eval
i exec
oba są wbudowane w polecenia bash (1), które wykonują polecenia.
Widzę też, że exec
ma kilka opcji, ale czy to jedyna różnica? Co dzieje się z ich kontekstem?
bash
shell
shell-builtin
Willian Paixao
źródło
źródło
Odpowiedzi:
eval
iexec
są zupełnie innymi zwierzętami. (Oprócz faktu, że oba będą uruchamiać polecenia, ale robi to wszystko, co robisz w powłoce).To
exec cmd
, co robi, jest dokładnie takie samo, jak tylko uruchamianiecmd
, z tą różnicą, że bieżąca powłoka jest zastępowana poleceniem, zamiast uruchamiania osobnego procesu. Uruchamianie say/bin/ls
wywoła wewnętrzniefork()
proces potomny, a następnieexec()
proces potomny/bin/ls
.exec /bin/ls
z drugiej strony nie rozwidli się, a jedynie zastępuje powłokę.Porównać:
z
echo $$
wypisuje PID powłoki, którą uruchomiłem, a listing/proc/self
daje nam PID tego,ls
który został uruchomiony z powłoki. Zwykle identyfikatory procesów są różne, aleexec
w powłocels
mają ten sam identyfikator procesu. Ponadto następujące polecenieexec
nie zostało uruchomione, ponieważ powłoka została zastąpiona.Z drugiej strony:
eval
uruchomi argumenty jako polecenie w bieżącej powłoce. Innymi słowyeval foo bar
to to samo co sprawiedliwefoo bar
. Ale zmienne zostaną rozszerzone przed wykonaniem, abyśmy mogli wykonywać polecenia zapisane w zmiennych powłoki:To będzie nie utworzy proces potomny, więc zmienna jest ustawiona w bieżącej powłoki. (Oczywiście
eval /bin/ls
stworzy proces potomny, tak samo jak zwykły stary/bin/ls
).Lub możemy mieć polecenie, które wyprowadza polecenia powłoki. Uruchamianie
ssh-agent
uruchamia agenta w tle i generuje wiązkę przypisań zmiennych, które mogą być ustawione w bieżącej powłoce i używane przez procesy potomne (ssh
polecenia, które uruchomisz). Dlategossh-agent
można rozpocząć od:Bieżąca powłoka pobierze zmienne dla innych poleceń do dziedziczenia.
Oczywiście, jeśli zmienna
cmd
zawiera coś podobnegorm -rf $HOME
, to uruchamianieeval "$cmd"
nie byłoby czymś, co chciałbyś zrobić. Nawet takie rzeczy jak zmiana dowodzenia wewnątrz łańcucha będą przetwarzane, więc trzeba naprawdę mieć pewność, że dane wejścioweeval
są bezpieczne przed użyciem.Często można uniknąć,
eval
a nawet przypadkowo pomieszać kod i dane w niewłaściwy sposób.źródło
eval
w pierwszej kolejności również do tej odpowiedzi. Rzeczy takie jak pośrednio modyfikujące zmienne można wykonać w wielu powłokach poprzezdeclare
/typeset
/nameref
i rozszerzenia takie jak${!var}
, więc użyłbym ich zamiast,eval
chyba że naprawdę musiałem tego unikać.exec
nie tworzy nowego procesu. To zastępuje bieżący proces z nową komendę. Jeśli zrobiłeś to w wierszu poleceń, to skutecznie zakończy sesję powłoki (a może wylogujesz się lub zamkniesz okno terminala!)na przykład
Oto jestem
ksh
(moja normalna powłoka). Zaczynam,bash
a potem w środkuexec /bin/echo
. Widzimy, że wróciłemksh
później, ponieważbash
proces został zastąpiony przez/bin/echo
.źródło
TL; DR
exec
służy do zastąpienia bieżącego procesu powłoki nowymi i obsługi przekierowań / deskryptorów plików, jeśli nie podano żadnej komendy.eval
służy do oceny ciągów jako poleceń. Oba mogą być użyte do zbudowania i wykonania polecenia z argumentami znanymi w czasie wykonywania, aleexec
oprócz wykonywania poleceń zastępuje proces bieżącej powłoki.exec buil-in
Składnia:
Zgodnie z instrukcją, jeśli istnieje polecenie określone to wbudowane
Innymi słowy, jeśli działałeś
bash
z PID 1234 i jeśli miałbyś działaćexec top -u root
w tej powłoce,top
polecenie będzie miało PID 1234 i zastąpi proces powłoki.Gdzie to jest przydatne? W czymś znanym jako skrypty opakowujące. Takie skrypty budują zestawy argumentów lub podejmują określone decyzje dotyczące zmiennych, które mają zostać przekazane do środowiska, a następnie wykorzystują je
exec
do zastąpienia dowolną określoną komendą i oczywiście podając te same argumenty, które zbudował skrypt opakowania.Instrukcja podaje również, że:
To pozwala nam przekierowywać wszystko z bieżących strumieni wyjściowych powłok do pliku. Może to być przydatne do rejestrowania lub filtrowania, gdzie nie chcesz widzieć
stdout
poleceń, a jedyniestderr
. Na przykład tak:To zachowanie sprawia, że jest to przydatne do logowania się w skryptach powłoki , przekierowywania strumieni do oddzielnych plików lub procesów oraz innych zabawnych rzeczy z deskryptorami plików.
Na poziomie kodu źródłowego przynajmniej dla
bash
wersji 4.3exec
wbudowany jest zdefiniowany wbuiltins/exec.def
. Analizuje otrzymane polecenia, a jeśli takie istnieją, przekazuje rzeczy doshell_execve()
funkcji zdefiniowanej wexecute_cmd.c
pliku.Krótko mówiąc, istnieje rodzina
exec
poleceń w języku programowania C ishell_execve()
jest to po prostu funkcja otokiexecve
:eval wbudowany
Ręczne ustawienia bash 4.3 (podkreślenie dodane przeze mnie):
Zauważ, że nie ma zamiany procesu. W przeciwieństwie do tego,
exec
gdzie celem jest symulacjaexecve()
funkcjonalności,eval
wbudowany służy tylko do „oceny” argumentów, tak jakby użytkownik wpisał je w wierszu poleceń. W związku z tym tworzone są nowe procesy.Gdzie to może być przydatne? Jak zauważył Gilles w tej odpowiedzi : „... eval nie jest używane bardzo często. W niektórych powłokach najczęstszym zastosowaniem jest uzyskanie wartości zmiennej, której nazwa jest znana dopiero po uruchomieniu”. Osobiście użyłem go w kilku skryptach na Ubuntu, gdzie konieczne było wykonanie / ocena polecenia w oparciu o konkretny obszar roboczy, z którego użytkownik aktualnie korzysta.
Na poziomie kodu źródłowego jest on zdefiniowany
builtins/eval.def
i przekazuje przeanalizowany ciąg wejściowy doevalstring()
funkcji.Między innymi
eval
może przypisywać zmienne, które pozostają w bieżącym środowisku wykonywania powłoki, podczas gdyexec
nie może:źródło
Oh, co? Chodzi o
eval
to, że w żaden sposób nie tworzy ono procesu potomnego. Jeśli zrobięw powłoce, a następnie bieżąca powłoka zmieni katalog. Ani też nie
exec
tworzy nowego procesu potomnego, zamiast tego zmienia bieżący plik wykonywalny (czyli powłokę) dla danego; identyfikator procesu (i otwarte pliki i inne rzeczy) pozostają takie same. W przeciwieństwie doeval
, anexec
nie powróci do powłoki wywołującej, chyba żeexec
sama zawiedzie z powodu niemożności znalezienia lub załadowania pliku wykonywalnego lub śmierci w wyniku problemów z rozszerzaniem argumentów.eval
w zasadzie interpretuje swoje argumenty jako ciąg po konkatenacji, mianowicie wykona dodatkową warstwę interpretacji symboli wieloznacznych i podziału argumentów.exec
nic takiego nie robi.źródło
Ocena
Te prace:
Nie powodują one jednak:
Zastąp proces obrazu
Ten przykład pokazuje, jak
exec
zastępuje obraz procesu wywoływania:Zauważ, że
exec echo $$
działał z PID podpowłoki! Co więcej, po jego zakończeniu wróciliśmy do naszej oryginalnejsh$
powłoki.Z drugiej strony,
eval
czy nie zastąpić obraz procesu. Raczej uruchamia podane polecenie, tak jak normalnie w samej powłoce. (Oczywiście, jeśli uruchomisz polecenie wymagające odrodzenia procesu ... robi to po prostu!)źródło
exec
)