태그 보관물: shell-builtin

shell-builtin

eval과 exec의 차이점은 무엇입니까? 실행하는 bash

eval그리고 exec명령을 실행하는 bash (1) 명령이 내장되어 있습니다.

또한 exec몇 가지 옵션이 있지만 유일한 차이점은 무엇입니까? 그들의 상황은 어떻게됩니까?



답변

evalexec완전히 다른 짐승이다. (둘 다 명령을 실행하지만 쉘에서 수행하는 모든 작업을 수행한다는 사실을 제외하고)

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

무엇 exec cmd않습니다, 단지 실행과 정확히 동일 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/selfls쉘에서 실행 된 PID를 제공합니다 . 일반적으로 프로세스 ID는 다르지만 exec쉘이 있고 ls프로세스 ID가 동일합니다. 또한 exec쉘이 교체되었으므로 다음 명령 이 실행되지 않았습니다.


반면에 :

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

eval현재 쉘에서 명령으로 인수를 실행합니다. 다시 말해서 eval foo bar, 그냥와 동일합니다 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 $HOMErunning eval "$cmd"은 원하지 않는 일입니다. 그래서 문자열 내부 명령 대체처럼 심지어 일들이 처리 될 사람이해야 정말 입력이 할 수 있는지 확인 eval을 사용하기 전에 안전합니다.

종종 eval실수로 코드와 데이터를 잘못 혼합하는 것을 피하고 피할 수 있습니다.


답변

exec새로운 프로세스를 만들지 않습니다. 그것은 대체하는 새로운 명령을 사용하여 현재 프로세스를. 명령 행에서이 작업을 수행하면 셸 세션이 효과적으로 종료됩니다 (그리고 로그 아웃하거나 터미널 창을 닫을 수도 있습니다).

예 :

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

여기에 있습니다 ksh(일반 쉘). 나는 bashbash를 시작 하고 시작한다 exec /bin/echo. 프로세스가로 교체 되었으므로 ksh나중에 다시 탈퇴 한 것을 확인할 수 있습니다 .bash/bin/echo


답변

TL; DR

exec명령이 지정되지 않은 경우 현재 쉘 프로세스를 새 것으로 대체하고 스트림 경로 재 지정 / 파일 디스크립터를 처리하는 데 사용됩니다. eval문자열을 명령으로 평가하는 데 사용됩니다. 둘 다 런타임에 알려진 인수로 명령을 빌드하고 실행하는 데 사용될 수 있지만 exec명령을 실행하는 것 외에도 현재 쉘의 프로세스를 대체합니다.

exec buil-in

통사론:

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

이 내장 명령이 지정된 경우 매뉴얼에 따라

… 쉘을 대체합니다. 새로운 프로세스가 생성되지 않습니다. 인수는 명령에 대한 인수가됩니다.

다시 말해, bashPID 1234 로 실행 중이고 exec top -u root해당 쉘 내 에서 실행 중이 면 top명령에 PID 1234가 있고 쉘 프로세스를 대체합니다.

이것은 어디에 유용합니까? 래퍼 스크립트라고합니다. 이러한 스크립트는 인수 세트를 작성하거나 환경에 전달할 변수에 대한 특정 결정을 내린 후 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합니다.

간단히 말해서 execC 프로그래밍 언어로 된 명령 계열이 shell_execve()있으며 기본적으로 다음과 같은 래퍼 함수입니다 execve.

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

eval 내장

bash 4.3 매뉴얼 상태 (내가 강조한 내용) :

인수는 읽고 단일 명령으로 함께 연결됩니다. 그런 다음이 명령을 에서 읽고 실행 하며 종료 상태는 eval 값으로 리턴됩니다.

프로세스 교체가 발생하지 않습니다. 기능 exec을 시뮬레이션하는 것이 목표 인 것과 달리 내장 execve()기능 eval은 마치 사용자가 명령 행에 인수를 입력 한 것처럼 인수를 “평가”하는 역할 만합니다. 따라서 새로운 프로세스가 생성됩니다.

이것이 유용한 곳은 어디입니까? Gilles 가이 답변에서 지적했듯이 “… eval은 자주 사용되지 않습니다. 일부 쉘에서 가장 일반적인 용도는 런타임까지 이름을 알 수없는 변수의 값을 얻는 것입니다.” 개인적으로, 나는 우분투에서 사용자가 현재 사용하고있는 특정 작업 공간을 기반으로 명령을 실행 / 평가 해야하는 두 스크립트에서 사용했습니다.

소스 코드 레벨에서 정의되고 builtins/eval.def구문 분석 된 입력 문자열을 evalstring()함수에 전달합니다 .

무엇보다도, eval변수에 할당 있는 동안은, 현재 쉘 실행 환경에 남아 exec할 수 없습니다 :

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

답변

새로운 자식 프로세스를 생성하고 인수를 실행하고 종료 상태를 반환합니다.

어? 요점은 eval자식 프로세스를 만들지 않는다는 것입니다. 만약 내가한다면

eval "cd /tmp"

쉘에서, 현재 쉘은 디렉토리를 변경했을 것입니다. 또한 exec새로운 자식 프로세스를 만들지 않고 주어진 실행 파일에 대한 현재 실행 파일 (즉, 셸)을 변경합니다. 프로세스 ID (및 열린 파일 및 기타 항목)는 동일하게 유지됩니다. 에 반대로 eval,는 exec하지 않는 호출 쉘에 반환하지 않습니다 exec자체가 실패로 인해 찾거나 실행 파일을로드하거나 인수 확장 문제에 죽을 수없는 존재로.

eval기본적으로 인수 후 인수를 문자열로 해석합니다. 즉, 와일드 카드 확장 및 인수 분할의 추가 계층을 수행합니다. exec그런 일은하지 않습니다.


답변

평가

이 작품들 :

$ 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

답변