누군가가 만든 bash 스크립트를 읽고 있었는데 작성자가
작성자가 사용한 명령처럼 변수를 평가하기 위해 eval을 사용하지 않는다는 것을 알았습니다.
bash -c "$1"
바꾸다
eval "$1"
나는 eval을 사용하는 것이 선호되는 방법이라고 생각하며 어쨌든 더 빠를 것입니다. 정말?
둘 사이에 실질적인 차이가 있나요? 둘 사이의 중요한 차이점은 무엇입니까?
답변1
eval "$1"
현재 스크립트에서 명령을 실행합니다. 현재 스크립트에서 쉘 변수를 설정 및 사용하고, 현재 스크립트의 환경 변수를 설정하고, 현재 스크립트에서 기능을 설정 및 사용하고, 현재 스크립트의 현재 디렉터리, umask, 제한 및 기타 속성을 설정할 수 있습니다. bash -c "$1"
환경 변수, 파일 설명자 및 기타 프로세스 환경을 상속하지만(변경 사항을 다시 전달하지 않음) 완전히 별도의 스크립트에서 명령을 실행하지만 내부 셸 설정(셸 변수, 함수, 옵션, 트랩 등)은 상속하지 않습니다. .
하위 쉘에서 명령을 실행하는 또 다른 방법이 있습니다 (eval "$1")
. 호출 스크립트에서 모든 것을 상속하지만 변경 사항을 다시 전달하지 않습니다.
예를 들어, 변수가 dir
내보내지지 않고 다음과 같다고 가정 $1
합니다 cd "$foo"; ls
.
cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
내용을 나열/somewhere/else
하고 인쇄하십시오/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
내용을 나열/somewhere/else
하고 인쇄하십시오/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
내용을 나열하고/starting/directory
(cd ""
현재 디렉토리는 변경되지 않으므로) 인쇄하십시오/starting/directory
.
답변2
가장 중요한 차이점은
bash -c "$1"
그리고
eval "$1"
전자는 서브셸에서 실행되지만 후자는 그렇지 않습니다. 그래서:
set -- 'var=something'
bash -c "$1"
echo "$var"
산출:
#there doesn't seem to be anything here
set -- 'var=something'
eval "$1"
echo "$var"
산출:
something
하지만 왜 누군가가 bash
이런 방식으로 실행 파일을 사용 하는지 모르겠습니다. 호출해야 한다면 내장된 POSIX를 사용하세요 sh
. 또는 (subshell eval)
환경을 보호하려면 .
.dot
개인적으로는 쉘을 더 선호합니다.
printf 'var=something%d ; echo "$var"\n' `seq 1 5` | . /dev/fd/0
산출
something1
something2
something3
something4
something5
하지만 정말 필요합니까?
실제로 이들 중 하나를 사용하는 유일한 이유는 변수가 실제로 다른 변수를 할당하거나 평가하거나 토큰화가 출력에 중요한 경우입니다.
예를 들어:
var='echo this is var' ; $var
산출:
this is var
이는 작동하지만 echo
매개변수 개수에 신경 쓰지 않기 때문입니다.
var='echo "this is var"' ; $var
산출:
"this is var"
바라보다? 쉘 확장 결과가 $var
평가되지 않기 때문에 큰따옴표가 나타납니다 quote-removal
.
var='printf %s\\n "this is var"' ; $var
산출:
"this
is
var"
그러나 다음을 사용 eval
하거나 sh
:
var='echo "this is var"' ; eval "$var" ; sh -c "$var"
산출:
this is var
this is var
eval
or 를 사용하면 sh
셸은 확장 결과에 대해 두 번째 전달을 수행하고 이를 잠재적인 명령으로도 평가하므로 따옴표가 다릅니다. 다음과 같이 할 수도 있습니다.
. <<VAR /dev/fd/0
${var:=echo "this is var"}
#END
VAR
산출
this is var
답변3
나는 간단한 테스트를 했다:
time bash -c 'for i in {1..10000}; do bash -c "/bin/echo hi"; done'
time bash -c 'for i in {1..10000}; eval "/bin/echo hi"; done'
(예, 알고 있습니다. bash -c를 사용하여 루프를 수행했지만 아무런 차이가 없습니다.)
결과:
eval : 1.17s
bash -c : 7.15s
그래서 eval
더 빠릅니다. 매뉴얼 페이지에서 eval
:
eval 유틸리티는 인수를 함께 연결하고 각 인수를 문자로 구분하여 명령을 구성해야 합니다. 생성된 명령은 쉘에서 읽고 실행해야 합니다.
bash -c
물론 bash 쉘에서 명령을 실행하십시오. 참고: 저는 이것이 내장된 쉘이기 /bin/echo
때문에 이것을 사용하고 있는데 , 이는 새로운 프로세스를 시작할 필요가 없다는 것을 의미합니다. 테스트를 위해 교체했는데 비용 이 다소 들었습니다 . 그러나 실행 파일을 실행하는 것이 더 빠릅니다. 여기서 가장 큰 차이점은 새 셸을 시작하는 대신(현재 셸에서 명령을 실행함) 새 셸을 시작한 다음 새 셸에서 명령을 실행한다는 것입니다. 새 셸을 시작하는 데는 시간이 걸리므 로 .echo
bash
/bin/echo
echo
bash -c
1.28s
eval
eval
bash -c
bash -c
eval