"eval"과 "source / dev / stdin"의 차이점은 무엇입니까?


17

다음 대안들 사이에서 ...

  1. eval.

    comd="ls"
    eval "$comd"
    
  2. source /dev/stdin

    printf "ls" | source /dev/stdin
  3. source /dev/stdin( )또는{ }

    ( printf "ls" ) | source /dev/stdin
    { printf "ls"; } | source /dev/stdin
    

    ( printf에서 실행할 때 { }서브 쉘을 사용하지 않는 것 외에 다른 이점이 있습니까?)

    • 그들 사이의 차이점은 무엇입니까?

    • 어느 것이 선호됩니까?

    • 명령을 실행하기 위해 선호되는 방법은 무엇입니까? ()또는 {}?


1
두 가지 방법 중 하나를 권장하지 않습니다. 실제로 무엇을하려고 합니까 , 사용자가 제출 한 임의의 코드를 실행해야한다고 생각하십니까?
chepner

2
또한 질문을 읽을 때까지 (있는 그대로) 임의의 사용자 입력을 실행하고 있었지만. 그러나 당신은 그들이 할 것이라고 예측하고있을 수 있습니다.
ctrl-alt-delor

답변:


17
  • 방법의 차이점은 무엇입니까?

부터 bash manpage:

eval [arg ...]
              The  args  are read and concatenated together into a single com
              mand.  This command is then read and executed by the shell,  and
              its  exit status is returned as the value of eval.  If there are
              no args, or only null arguments, eval returns 0.

source filename [arguments]
              Read and execute commands from filename  in  the  current  shell
              environment  and return the exit status of the last command exe
              cuted from filename.  If filename does not contain a slash, file
              names  in  PATH  are used to find the directory containing file
              name.  The file searched for in PATH  need  not  be  executable.
              When  bash  is  not  in  posix  mode,  the  current directory is
              searched if no file is found in PATH.  If the sourcepath  option
              to  the  shopt  builtin  command  is turned off, the PATH is not
              searched.  If any arguments are supplied, they become the  posi
              tional  parameters  when  filename  is  executed.  Otherwise the
              positional parameters are unchanged.  The return status  is  the
              status  of  the  last  command exited within the script (0 if no
              commands are executed), and false if filename is  not  found  or
              cannot be read.

두 방법 사이에는 차이가 없습니다.

단 하나의 메모가 있습니다. eval모든 인수를 연결 한 다음 단일 명령으로 실행됩니다. source파일의 내용을 읽고 실행합니다. eval인수가 아닌 명령 만 작성할 수 있습니다 stdin. 따라서 다음과 같이 할 수 없습니다 :

printf "ls" | eval
  • 어느 것이 더 선호됩니까?

귀하의 예는 동일한 결과를 제공하지만 목적 evalsource는 다릅니다. source일반적으로 다른 스크립트에 라이브러리를 제공하는 eval데 사용되는 반면 명령 평가에만 사용됩니다. 회피 된 eval끈이 깨끗하다는 보장이 없기 때문에 가능하면 사용을 피해야 합니다. 우리는 subshell대신 에를 사용하여 위생 검사를 수행해야합니다 .

  • () 또는 {}에서 일부 명령을 실행하면 어떤 것이 더 선호됩니까?

중괄호 안에서 시퀀스 명령을 실행하면 { }모든 명령이 서브 쉘 대신 현재 쉘 에서 실행됩니다 (괄호 안에서 실행하는 경우 (bash 참조 )).

사용하면 subshell ( )더 많은 리소스가 사용되지만 현재 환경에는 영향을 미치지 않습니다. 사용 { }은 현재 쉘에서 모든 명령을 실행하므로 환경에 영향을줍니다. 목적에 따라 그중 하나를 선택할 수 있습니다.


2
나는 당신이 그 질문을 오해했다고 생각합니다. 물론, 당신은 대체 할 수 evalsource. 질문은 다음 eval "$cmd"과 같습니다 echo "$cmd" | source /dev/stdin. 나의 현재 의견은 : 그렇습니다.
Hauke ​​Laging

3

가장 큰 차이점은 두 번째와 세 번째 형식은 파이프를 사용한다는 것입니다. 이로 인해 bash는 서브 쉘에서 "source"명령을 강제 실행합니다 (lastpipe가 설정되어 있고 bash 4.2 이상에서만 사용 가능하지 않은 경우). :

printf "ls" | bash

결과적으로 코드에서 설정 한 환경 변수가 손실되므로 예상대로 작동하지 않습니다.

printf "abc=2" | source /dev/stdin

현재 쉘에서 명령을 실행하려면 프로세스 대체를 사용할 수 있습니다.

source <(printf "abc=2")

평소처럼 세미콜론을 사용하여 괄호 안에 더 많은 명령을 넣을 수 있습니다.

이 방법으로 파이프를 제거하면 "eval"과 "source"사용에 차이가 없다고 생각합니다. 특정한 경우에 사용하기 쉬운 것을 선호해야합니다.

  • 변수에서 실행할 명령이 이미있는 경우 "eval"을 사용하십시오.
  • 파일에 있거나 외부 명령에서 가져 오는 경우 "source"를 사용하십시오.

0

이미 주어진 답변을 보완하기 위해 :

source해당하는 ...

comd="ls"
eval "$comd"

~는 ・ ・ ・

source <(printf ls)

ls큰 차이가없는 경우 .

그러나 현재 환경영향미치는 명령 (일반적으로 사용 할 때 의도 한 source것)의 경우이 변형은 (첫 번째 솔루션과 eval마찬가지로) 수행하지만 두 번째 접근 방식은 하위 쉘의 환경에만 영향을 미칩니다. 코드를 실행 한 후에는 사용할 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.