Jaka jest różnica między eval a exec?


Odpowiedzi:


124

evali execsą zupełnie innymi zwierzętami. (Oprócz faktu, że oba będą uruchamiać polecenia, ale robi to wszystko, co robisz w powłoce).

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

To exec cmd, co robi, jest dokładnie takie samo, jak tylko uruchamianie cmd, z tą różnicą, że bieżąca powłoka jest zastępowana poleceniem, zamiast uruchamiania osobnego procesu. Uruchamianie say /bin/lswywoła wewnętrznie fork()proces potomny, a następnie exec()proces potomny /bin/ls. exec /bin/lsz drugiej strony nie rozwidli się, a jedynie zastępuje powłokę.

Porównać:

$ bash -c 'echo $$ ; ls -l /proc/self ; echo foo'
7218
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7219
foo

z

$ bash -c 'echo $$ ; exec ls -l /proc/self ; echo foo'
7217
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7217

echo $$wypisuje PID powłoki, którą uruchomiłem, a listing /proc/selfdaje nam PID tego, lsktóry został uruchomiony z powłoki. Zwykle identyfikatory procesów są różne, ale execw powłoce lsmają ten sam identyfikator procesu. Ponadto następujące polecenie execnie zostało uruchomione, ponieważ powłoka została zastąpiona.


Z drugiej strony:

$ help eval
eval: eval [arg ...]
    Execute arguments as a shell command.

evaluruchomi argumenty jako polecenie w bieżącej powłoce. Innymi słowy eval foo barto to samo co sprawiedliwe foo bar. Ale zmienne zostaną rozszerzone przed wykonaniem, abyśmy mogli wykonywać polecenia zapisane w zmiennych powłoki:

$ unset bar
$ cmd="bar=foo"
$ eval "$cmd"
$ echo "$bar"
foo

To będzie nie utworzy proces potomny, więc zmienna jest ustawiona w bieżącej powłoki. (Oczywiście eval /bin/lsstworzy proces potomny, tak samo jak zwykły stary /bin/ls).

Lub możemy mieć polecenie, które wyprowadza polecenia powłoki. Uruchamianie ssh-agenturuchamia 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 ( sshpolecenia, które uruchomisz). Dlatego ssh-agentmożna rozpocząć od:

eval $(ssh-agent)

Bieżąca powłoka pobierze zmienne dla innych poleceń do dziedziczenia.


Oczywiście, jeśli zmienna cmdzawiera coś podobnego rm -rf $HOME, to uruchamianie eval "$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ściowe evalsą bezpieczne przed użyciem.

Często można uniknąć, evala nawet przypadkowo pomieszać kod i dane w niewłaściwy sposób.


To świetna odpowiedź, @ilkkachu. Dzięki!
Willian Paixao

Więcej informacji na temat korzystania z eval można znaleźć tutaj: stackoverflow.com/a/46944004/2079103
clearlight

1
@ Clearlight, cóż, to przypomina mi, aby dodać zwykłe zastrzeżenie dotyczące nieużywania evalw pierwszej kolejności również do tej odpowiedzi. Rzeczy takie jak pośrednio modyfikujące zmienne można wykonać w wielu powłokach poprzez declare/ typeset/ namerefi rozszerzenia takie jak ${!var}, więc użyłbym ich zamiast, evalchyba że naprawdę musiałem tego unikać.
ilkkachu

27

execnie 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

ksh% bash
bash-4.2$ exec /bin/echo hello
hello
ksh% 

Oto jestem ksh(moja normalna powłoka). Zaczynam, basha potem w środku exec /bin/echo. Widzimy, że wróciłem kshpóźniej, ponieważ bashproces został zastąpiony przez /bin/echo.


umm na twarzy wrócił do procesu ksh b / c został zastąpiony przez echo czy to nie ma sensu?

14

TL; DR

execsł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. evalsł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, ale execoprócz wykonywania poleceń zastępuje proces bieżącej powłoki.

exec buil-in

Składnia:

exec [-cl] [-a name] [command [arguments]]

Zgodnie z instrukcją, jeśli istnieje polecenie określone to wbudowane

... zastępuje powłokę. Nie jest tworzony nowy proces. Argumenty stają się argumentami do dowodzenia.

Innymi słowy, jeśli działałeś bashz PID 1234 i jeśli miałbyś działać exec top -u rootw tej powłoce, toppolecenie 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 execdo zastąpienia dowolną określoną komendą i oczywiście podając te same argumenty, które zbudował skrypt opakowania.

Instrukcja podaje również, że:

Jeśli polecenie nie zostanie określone, wszelkie przekierowania zostaną zastosowane w bieżącej powłoce

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ć stdoutpoleceń, a jedynie stderr. Na przykład tak:

bash-4.3$ exec 3>&1
bash-4.3$ exec > test_redirect.txt
bash-4.3$ date
bash-4.3$ echo "HELLO WORLD"
bash-4.3$ exec >&3
bash-4.3$ cat test_redirect.txt 
2017 05 20 星期六 05:01:51 MDT
HELLO WORLD

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 bashwersji 4.3 execwbudowany jest zdefiniowany w builtins/exec.def. Analizuje otrzymane polecenia, a jeśli takie istnieją, przekazuje rzeczy do shell_execve()funkcji zdefiniowanej w execute_cmd.cpliku.

Krótko mówiąc, istnieje rodzina execpoleceń w języku programowania C i shell_execve()jest to po prostu funkcja otoki execve:

/* Call execve (), handling interpreting shell scripts, and handling
   exec failures. */
int
shell_execve (command, args, env)
     char *command;
     char **args, **env;
{

eval wbudowany

Ręczne ustawienia bash 4.3 (podkreślenie dodane przeze mnie):

Argumenty są odczytywane i łączone w jedno polecenie. To polecenie jest następnie odczytywane i wykonywane przez powłokę , a jego status wyjścia jest zwracany jako wartość eval.

Zauważ, że nie ma zamiany procesu. W przeciwieństwie do tego, execgdzie celem jest symulacja execve()funkcjonalności, evalwbudowany 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.defi przekazuje przeanalizowany ciąg wejściowy do evalstring()funkcji.

Między innymi evalmoże przypisywać zmienne, które pozostają w bieżącym środowisku wykonywania powłoki, podczas gdy execnie może:

$ eval x=42
$ echo $x
42
$ exec x=42
bash: exec: x=42: not found

@ ctrl-alt-delor Zredagowałem tę część, dzięki, chociaż prawdopodobnie odradza się nowy proces, PID pozostaje po prostu taki sam jak w obecnej powłoce. W przyszłości zastanów się nad edytowaniem odpowiedzi, zamiast pozostawiać komentarz i głosować, szczególnie w przypadku tak drobnych rzeczy, jak 7-wyrazowa fraza; edytowanie i poprawianie odpowiedzi jest o wiele mniej czasochłonne i znacznie bardziej pomocne.
Sergiy Kolodyazhnyy

5
tworząc nowy proces potomny, uruchom argumenty i zwróć status wyjścia.

Oh, co? Chodzi o evalto, że w żaden sposób nie tworzy ono procesu potomnego. Jeśli zrobię

eval "cd /tmp"

w powłoce, a następnie bieżąca powłoka zmieni katalog. Ani też nie exectworzy 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 do eval, an execnie powróci do powłoki wywołującej, chyba że execsama zawiedzie z powodu niemożności znalezienia lub załadowania pliku wykonywalnego lub śmierci w wyniku problemów z rozszerzaniem argumentów.

evalw zasadzie interpretuje swoje argumenty jako ciąg po konkatenacji, mianowicie wykona dodatkową warstwę interpretacji symboli wieloznacznych i podziału argumentów. execnic takiego nie robi.


1
Pierwotne pytanie brzmiało: „eval i exec są wbudowanymi poleceniami Bash (1) i wykonują polecenia, tworząc nowy proces potomny, uruchamiając argumenty i zwracając status wyjścia”; Zredagowałem fałszywe domniemanie.
Charles Stewart,

-1

Ocena

Te prace:

$ echo hi
hi

$ eval "echo hi"
hi

$ exec echo hi
hi

Nie powodują one jednak:

$ exec "echo hi"
bash: exec: echo hi: not found

$ "echo hi"
bash: echo hi: command not found

Zastąp proces obrazu

Ten przykład pokazuje, jak execzastępuje obraz procesu wywoływania:

# Get PID of current shell
sh$ echo $$
1234

# Enter a subshell with PID 5678
sh$ sh

# Check PID of subshell
sh-subshell$ echo $$
5678

# Run exec
sh-subshell$ exec echo $$
5678

# We are back in our original shell!
sh$ echo $$
1234

Zauważ, że exec echo $$działał z PID podpowłoki! Co więcej, po jego zakończeniu wróciliśmy do naszej oryginalnej sh$powłoki.

Z drugiej strony, evalczy 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!)

sh$ echo $$
1234

sh$ sh

sh-subshell$ echo $$
5678

sh-subshell$ eval echo $$
5678

# We are still in the subshell!
sh-subshell$ echo $$
5678

Wysłałem tę odpowiedź, ponieważ inne przykłady tak naprawdę nie ilustrują tego w wystarczająco zrozumiały sposób dla słabych umysłów, takich jak I.
Mateen Ulhaq

Niewłaściwy wybór słów: podstawianie procesów to istniejące pojęcie, które wydaje się nie mieć związku z tym, co tutaj ilustrujesz.
muru

@muru Czy „wymiana procesu” jest lepsza? Nie jestem pewien, jaka jest poprawna terminologia. Strona man wydaje się nazywać to „zastępowaniem obrazu procesu”.
Mateen Ulhaq

Hmm, nie wiem. (Ale kiedy słyszę „zastąpienie obrazu procesu”, myślę: exec)
Muru
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.