자택경비대

bash에서 exec와 eval의 차이는 무엇일까?

stackoverflow

evalexec는 둘다 bash(1)의 내장 명령어 입니다.
exec가 몇 가지 다른 옵션을 가지고 있는것은 알지만 둘의 차이점은 무엇인가요?


evalexec는 완전히 다른 명령어라고 보셔도 됩니다.

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

exec cmd가 하는 일은, 그냥 cmd를 실행 했을때와 완전히 동일합니다.
다만, 다른 프로세스를 띄워서 명령어를 실행하는것이 아닌, 현재의 쉘을 명령어로 대체하게 됩니다.
내부적으로는, 예를들어 /bin/ls를 실행 할 경우 fork()를 호출하여서 자식 프로세스를 만든 후에 생성된 자식 프로세스 내에서 exec()를 재호출해서 /bin/ls를 실행하게 됩니다. exec /bin/ls는 이 과정(fork() 호출)을 거치지 않고 명령어를 실행하게 됩니다.

아래의 두 예제를 봅시다.
1.

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

2.

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

echo $$ 명령어는 처음에 명령어를 호출한 쉘의 PID값을 출력하게 됩니다. 그리고 /proc/self를 대상으로 ls 명령어로 리스팅을 하게 되면 명령어를 실행하는 프로세스의 PID를 가져올 수 있습니다. 일반적으로, (1)에서 볼 수 있듯이 두 PID는 다른 값을 가지게 되지만, exec를 통해 실행된 명령은 같은 PID를 갖는 것을 알 수 있습니다.
또한, exec명령어가 현재의 쉘을 완전히 대체하였기 때문에, 뒤 따르는 echo foo 명령이 실행되지 않은 것도 확인할 수 있습니다.

한편,

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

eval명령어는 인자를 받아서 현재의 쉘에서 실행하게 됩니다. 쉽게 말하면 eval foo barfoo bar은 완전히 같다 볼 수 있습니다.
다만, 변수들이 명령어가 실행되기 전에 확장되어 변수에 담겨있는 명령어를 실행하는 것이 가능해집니다.

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