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

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

다음 옵션 사이에서...

  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

다양한 방법의 차이점은 무엇입니까?

에서 man bash:

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

어느 것이 더 선호됩니까?

eval귀하의 예는 동일한 결과를 제공하지만 목적은 다릅니다 source. source일반적으로 다른 스크립트에 대한 라이브러리를 제공하는 데 사용되지만 eval명령 평가에만 사용됩니다. 'ed 문자열은 깨끗하다고 ​​보장되지 않으므로 eval가능하면 피해야 합니다 .evalsubshell

()또는 에서 일부 명령을 실행하면 {}어느 것이 더 바람직합니까?

명령 시퀀스가 ​​중괄호 안에 실행되면 { }모든 명령이 실행됩니다.현재 쉘, 바꾸다서브쉘(이것은 괄호 안에 실행하면 발생합니다(bash 참조).인용하다)).

이를 사용하면 subshell ( )더 많은 리소스가 필요하지만 현재 환경에는 영향을 미치지 않습니다. 를 사용하면 { }현재 셸의 모든 명령이 실행되므로 환경이 영향을 받습니다. 어느 것을 선택하느냐는 목적에 따라 다릅니다.

답변2

주요 차이점은 두 번째와 세 번째 양식은 파이프를 사용한다는 것입니다. 그러면 bash가 서브셸에서 "source" 명령을 실행하게 됩니다(Lastpipe가 설정되지 않은 경우 bash 4.2+에서만 사용 가능). 이는 거의 다음과 같습니다.

printf "ls" | bash

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

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

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

source <(printf "abc=2")

평소와 같이 세미콜론을 사용하여 괄호 안에 더 많은 명령을 입력할 수 있습니다.

이런 식으로 파이프를 제거하면 "eval"과 "source"를 사용하는 것 사이에 차이가 없다고 생각합니다. 특별한 경우에는 더 간단한 것을 사용하는 것이 좋습니다.

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

답변3

이미 제공된 답변에 추가로:

동등하다 source...

comd="ls"
eval "$comd"

... 예...

source <(printf ls)

경우에는 ls큰 차이가 없습니다 .

그러나 명령의 목적이 다음과 같다면현재 환경에 영향을 미침(코드 줄을 사용할 때 일반적으로 원하는 source것은 eval그 후에는 사용할 수 없습니다.

답변4

아직 이루어지지 않은 중요한 차이점이 있습니다!

❯ echo return | . /dev/stdin

❯ echo return | eval "$(cat -)"
sh: return: can only `return' from a function or sourced script

즉, return스크립트를 소싱할 때만 작동합니다.

스크립트의 내용과 의도에 따라 어느 것을 선택하든 상관없겠지만 차이점은 지적할 가치가 있다고 생각합니다.


eval위의 파이프 대신 파이프를 사용한 이유는 두 가지입니다 eval return.

  1. 파이프를 통해 들어가는 것이 가능하다는 것을 증명하기 위해서입니다 eval.

  2. 일관성을 위해 sourceso 및 둘 다 eval서브셸(파이프라인) 내에서 실행될 수 있습니다.

    예를 들어, 다음과 같이 시도한다면:

    ❯ echo a=1 | . /dev/stdin; echo $a
    ❯ echo a=1 | eval "$(cat -)"; echo $a
    

    1현재 환경에서 평가되지 않기 때문에 인쇄되지 않는 것을 알 수 있습니다 . 인쇄 하려면 다음을 수행해야 합니다 1.

    ❯ echo a=1 | { . /dev/stdin; echo $a; }
    ❯ echo a=1 | { eval "$(cat -)"; echo $a; }
    

관련 정보