bash -c를 사용한 명령으로서의 변수

bash -c를 사용한 명령으로서의 변수

누군가가 만든 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

evalor 를 사용하면 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때문에 이것을 사용하고 있는데 , 이는 새로운 프로세스를 시작할 필요가 없다는 것을 의미합니다. 테스트를 위해 교체했는데 비용 이 다소 들었습니다 . 그러나 실행 파일을 실행하는 것이 더 빠릅니다. 여기서 가장 큰 차이점은 새 셸을 시작하는 대신(현재 셸에서 명령을 실행함) 새 셸을 시작한 다음 새 셸에서 명령을 실행한다는 것입니다. 새 셸을 시작하는 데는 시간이 걸리므 로 .echobash/bin/echoechobash -c1.28sevalevalbash -cbash -ceval

관련 정보