명령으로 변수; 평가 대 bash -c


41

나는 bash는 스크립트 사람이 만든 읽고 있던 나는 저자가 명령으로 변수를 평가하는 평가 사용하지 않는 것으로 나타났습니다
저자는 사용을

bash -c "$1"

대신에

eval "$1"

나는 eval을 사용하는 것이 선호되는 방법이라고 가정하고 어쨌든 더 빠를 것입니다. 그게 사실입니까?
둘 사이에 실질적인 차이가 있습니까? 이 둘의 차이점은 무엇입니까?


어떤 경우에는 어느 쪽도없이 도망 갈 수 있습니다. e='echo foo'; $e잘 작동합니다.
Dennis

답변:


40

eval "$1"현재 스크립트에서 명령을 실행합니다. 현재 스크립트에서 쉘 변수를 설정 및 사용하고, 현재 스크립트에 대한 환경 변수를 설정하고, 현재 스크립트에서 기능을 설정 및 사용하고, 현재 디렉토리에 대한 현재 디렉토리, umask, limit 및 기타 속성을 설정하는 등의 작업을 수행 할 수 있습니다. 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.

감사. 몰랐습니다 (평가 "$ 1"), 소스와 다른가요?
whoami

1
@whoami (eval "$1")는 아무 관련 이 없습니다 source. 그것은 단지의 조합이다 (…)eval. source foo대략과 같습니다 eval "$(cat foo)".
Gilles 'SO- 악마 그만해'

우리는 동시에 우리의 답변을
써야

@whoami의 주요 차이점 eval과는 .doteval와 작품 의 인수.dot함께 작동 파일입니다.
mikeserv

둘 다 고마워 나의 이전의 의견은 내가 다시 읽었을 때 좀 어리석은 것 같습니다 ...
whoami

23

가장 중요한 차이점

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또는 sh쉘은 확장 결과에서 두 번째 단계를 거쳐 잠재적 인 명령으로 평가하므로 따옴표는 차이를 만듭니다. 당신은 또한 할 수 있습니다 :

. <<VAR /dev/fd/0
    ${var:=echo "this is var"}
#END
VAR

산출

this is var

5

나는 빠른 테스트를했다 :

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:

평가 유틸리티는 인수를 서로 연결하여 각 문자를 분리하여 명령을 구성해야합니다. 작성된 명령은 쉘에 의해 읽고 실행되어야합니다.

bash -c물론, bash 쉘에서 명령을 실행합니다. 참고 사항 :에 내장 된 쉘 /bin/echo이므로 새 프로세스를 시작할 필요가 없으므로 사용했습니다. 교체 로 에 대한 테스트, 그것은했다 . 그것은 거의 같습니다. Hovever 는 실행 파일 실행 속도가 빠릅니다. 여기서 중요한 차이점은 새 쉘을 시작하지 않고 (현재 쉘에서 명령을 실행) 새 쉘을 시작한 다음 새 쉘에서 명령을 실행한다는 것입니다. 새 셸을 시작하는 데 시간이 걸리므로 . 보다 느립니다 .echobash/bin/echoechobash -c1.28sevalevalbash -cbash -ceval


나는 OP 비교하고자하는 생각 bash -c과 함께 eval하지 exec.
Joseph R.

@JosephR. 죄송합니다! 변경하겠습니다.
PlasmaPower

1
@JosephR. 지금 수정해야합니다. 또한 나는 좀 더 테스트를 redid 및 bash -c아닌 ... 나쁜
PlasmaPower

3
이것은 사실이지만 다른 환경에서 명령이 실행되는 근본적인 차이점을 놓치고 있습니다. 새로운 bash 인스턴스를 시작하는 것이 느리다는 것은 분명하지만 이것은 흥미로운 관찰이 아닙니다.
Gilles 'SO- 악마 그만해'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.