eval
둘 exec
다 명령을 실행하는 bash(1) 명령에 내장되어 있습니다.
또한 exec
몇 가지 옵션이 있지만 그것이 유일한 차이점입니까? 그들의 배경은 어떻게 되나요?
답변1
eval
exec
완전히 다른 짐승 입니다 . (둘 모두 명령을 실행한다는 사실을 제외하면 셸에서 수행하는 모든 작업도 마찬가지입니다.)
$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
Replace the shell with the given command.
별도의 프로세스를 실행하는 대신 현재 셸이 명령으로 대체된다는 점을 제외하면 exec cmd
run 과 정확히 동일한 작업을 수행합니다 . cmd
내부적으로 say를 실행하면 자식 프로세스가 생성되고 /bin/ls
자식 프로세스에서 실행됩니다 . 반면에, 그것은fork()
exec()
/bin/ls
exec /bin/ls
아니요포크지만 껍질만 교체하면 됩니다.
비교하다:
$ bash -c 'echo $$ ; ls -l /proc/self ; echo foo'
7218
lrwxrwxrwx 1 root root 0 Jun 30 16:49 /proc/self -> 7219
foo
그리고
$ 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
우리가 실행한 셸의 PID가 표시됩니다. ls
일반적으로 프로세스 ID는 다르지만 exec
쉘 과 ls
동일한 프로세스 ID를 갖습니다 . 또한 exec
셸이 교체되었기 때문에 다음 명령이 실행되지 않습니다.
반면에:
$ help eval
eval: eval [arg ...]
Execute arguments as a shell command.
eval
인수는 현재 셸에서 명령으로 실행됩니다. 즉, eval foo bar
just 와 같습니다 foo bar
. 그러나 변수는 실행 전에 확장되므로 쉘 변수에 저장된 명령을 실행할 수 있습니다.
$ unset bar
$ cmd="bar=foo"
$ eval "$cmd"
$ echo "$bar"
foo
그럴 것이다아니요이 변수가 현재 셸에 설정되도록 하위 프로세스를 만듭니다. ( eval /bin/ls
물론 하위 프로세스는 기존 프로세스와 마찬가지로 생성됩니다 /bin/ls
.)
또는 쉘 명령을 출력하는 명령을 가질 수도 있습니다. Running은 백그라운드에서 에이전트를 시작하고 현재 셸에서 설정하고 하위 프로세스( 실행할 명령) ssh-agent
에서 사용할 수 있는 여러 변수 할당을 출력합니다 . ssh
따라서 ssh-agent
다음부터 시작하세요:
eval $(ssh-agent)
그리고 현재 쉘은 다른 명령에 의해 상속된 변수를 얻습니다.
물론 변수에 cmd
그런 내용이 포함되어 있으면 rm -rf $HOME
실행을 eval "$cmd"
원하지 않습니다. 문자열 내의 명령 대체와 같은 것까지 처리되므로해야 한다진짜eval
사용하기 전에 입력 내용이 안전한지 확인하세요.
종종 eval
실수로 코드와 데이터를 잘못된 방식으로 혼합하는 것을 방지할 수도 있습니다.
답변2
exec
새로운 프로세스가 생성되지 않습니다. 그것바꾸다새 명령을 사용하는 현재 프로세스입니다. 명령줄에서 이 작업을 수행하면 쉘 세션이 효과적으로 종료됩니다(로그아웃하거나 터미널 창을 닫을 수도 있습니다!).
예를 들어
ksh% bash
bash-4.2$ exec /bin/echo hello
hello
ksh%
여기 있습니다 ksh
(나의 일반적인 껍질). 나는 시작한 bash
다음 bash exec /bin/echo
I 에서 시작했습니다. 프로세스가 로 대체되었기 ksh
때문에 나중에 반환되었음을 알 수 있습니다 .bash
/bin/echo
답변3
긴 이야기 짧게
exec
명령이 지정되지 않으면 현재 셸 프로세스를 새 셸 프로세스로 바꾸고 스트림 리디렉션/파일 설명자를 처리합니다. eval
문자열을 명령으로 평가하는 데 사용됩니다. 둘 다 런타임에 알려진 매개변수를 사용하여 명령을 작성하고 실행하는 데 사용할 수 있지만 exec
명령을 실행하는 것 외에도 현재 셸의 프로세스도 대체합니다.
내장 실행
통사론:
exec [-cl] [-a name] [command [arguments]]
매뉴얼에 따르면 이 내장 명령이 지정되어 있는지 여부
...케이스를 교체하세요. 새로운 프로세스가 생성되지 않습니다. 이러한 매개변수는 명령의 매개변수가 됩니다.
즉, PID 1234로 실행하고 해당 셸에서 실행 bash
하려는 경우 명령은 PID 1234를 가지며 셸 프로세스를 대체합니다.exec top -u root
top
이것의 용도는 무엇입니까? 래퍼 스크립트라는 것에서. 이러한 스크립트는 매개변수 세트를 구축하거나 환경에 전달할 변수에 대한 결정을 내린 다음 exec
지정된 명령으로 자신을 대체하고 물론 래퍼 스크립트가 프로세스에서 구축한 것과 동일한 매개변수를 제공합니다.
설명서에는 다음과 같이 명시되어 있습니다.
명령이 지정되지 않으면 모든 리디렉션이 현재 셸에 적용됩니다.
이를 통해 현재 쉘의 출력 스트림에 있는 모든 내용을 파일로 리디렉션할 수 있습니다. 이는 명령을 보고 싶지 않지만 stdout
보기만 원하는 경우 로깅 또는 필터링 목적으로 유용할 수 있습니다 stderr
. 예를 들면 다음과 같습니다.
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
이 동작은 매우 편리합니다.로그인 쉘 스크립트, 스트림을 별도의 파일로 리디렉션하거나프로세스, 다른 사람재미있는 것들파일 설명자와 함께.
적어도 bash
버전 4.3의 소스 코드 수준 에서는 exec
내장 함수가 에 있습니다 builtins/exec.def
. 이는 수신된 명령을 구문 분석하고 해당 내용이 있는 경우 shell_execve()
파일에 정의된 함수에 전달합니다.execute_cmd.c
간단히 말해서 C 프로그래밍 언어에는 기본적으로 다음을 위한 래퍼 함수인 exec
일련의 명령이 있습니다 .shell_execve()
execve
/* Call execve (), handling interpreting shell scripts, and handling
exec failures. */
int
shell_execve (command, args, env)
char *command;
char **args, **env;
{
평가 내장
bash 4.3 매뉴얼에는 다음과 같이 명시되어 있습니다(강조 항목이 추가됨).
args를 읽고 함께 연결하여 명령을 형성합니다. 그런 다음 명령을 읽고 쉘에 의해 실행됨, 종료 상태가 eval 값으로 반환됩니다.
프로세스 교체는 발생하지 않습니다. 함수를 exec
시뮬레이션하는 목적 과 달리 내장 함수는 마치 사용자가 명령줄에 인수를 입력하는 것처럼 인수를 "평가"하는 데만 사용됩니다. 이런 식으로 새로운 프로세스가 생성됩니다.execve()
eval
이것이 어디에 유용할까요? Giles가 지적했듯이이 답변에서, "...eval은 일반적으로 사용되지 않습니다. 일부 쉘에서는 런타임까지 이름을 알 수 없는 변수의 값을 얻는 것이 가장 일반적으로 사용됩니다." 개인적으로 저는 사용자가 현재 사용하고 있는 특정 작업 공간을 기반으로 명령을 실행/평가해야 하는 Ubuntu의 여러 스크립트에서 이것을 사용했습니다.
소스 코드 수준에서는 builtins/eval.def
구문 분석된 입력 문자열을 정의하고 evalstring()
함수에 전달합니다.
무엇보다도 다음을 eval
수행할 수 있습니다.변수 할당현재 셸 실행 환경을 유지하지만 exec
다음을 수행할 수는 없습니다.
$ eval x=42
$ echo $x
42
$ exec x=42
bash: exec: x=42: not found
답변4
평가하다
이러한 작업은 다음과 같습니다.
$ echo hi
hi
$ eval "echo hi"
hi
$ exec echo hi
hi
그러나 다음은 그렇지 않습니다.
$ exec "echo hi"
bash: exec: echo hi: not found
$ "echo hi"
bash: echo hi: command not found
이미지 교체 처리
exec
이 예에서는 호출 프로세스의 이미지를 바꾸는 방법을 보여줍니다 .
# 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
exec echo $$
서브쉘의 PID를 사용하여 실행된다는 점에 유의하세요 ! 또한 완료되면 원래 셸로 돌아갑니다 sh$
.
반면에 eval
,아니요프로세스 이미지를 교체합니다. 대신, 쉘 자체 내에서 정상적으로 주어진 명령을 실행합니다. (물론, 프로세스 생성이 필요한 명령을 실행하는 경우...그렇게 됩니다!)
sh$ echo $$
1234
sh$ sh
sh-subshell$ echo $$
5678
sh-subshell$ eval echo $$
5678
# We are still in the subshell!
sh-subshell$ echo $$
5678