답변:
이것은 평가가 어떻게 작동하는지에 대한 질문으로 귀결됩니다. 두 예제 모두 같은 방식으로 작동하지만 셸 (bash, here)이 변수를 확장하는 방식으로 인해 문제가 발생합니다.
이 명령을 작성할 때 :
HOME="foo" echo $HOME
는 $HOME
확장 명령이 실행되기 전에 . 따라서 명령에 대해 설정 한 새 값이 아니라 원래 값으로 확장됩니다. HOME
변수는 실제로 그 환경에서 변경되었습니다 echo
명령은 그러나, 당신은을 인쇄에서 실행 $HOME
부모에서.
설명하기 위해 이것을 고려하십시오.
$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon
위에서 볼 수 있듯이 첫 번째 명령은 일시적으로 변경된 값을 HOME
인쇄하고 두 번째 명령 은 원본을 인쇄하여 변수가 일시적으로 만 변경되었음을 보여줍니다. 때문에 bash -c ...
명령 (작은 따옴표로 묶여 ' '
대신 두 사람 (의) " "
), 변수는 확장되지 않은 새로운 bash는 프로세스에 그대로 전달됩니다. 그런 다음이 새 프로세스는 프로세스를 확장하고 설정된 새 값을 인쇄합니다. 다음을 사용하면 이런 일이 발생할 수 있습니다 set -x
.
$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello
+ echo hello
hello
위에서 볼 수 있듯이 변수 $HOME
는에 전달되지 않습니다 echo
. 확장 된 값만 볼 수 있습니다. 다음과 비교하십시오 :
$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello
여기서 작은 따옴표로 인해 변수가 아니라 변수가 새 프로세스로 전달됩니다.
쉘이 라인을 구문 분석 할 때, 라인을 단어로 토큰 화하고 단어에 대해 다양한 확장 (순서대로)을 수행 한 다음 명령을 실행합니다.
가정 test=1:2:3:4:5:6
이 명령을 보자 : IFS=":" read a b c d e f <<< "$test"
토큰 화 후 매개 변수 확장이 발생합니다.IFS=":"
read
a
b
c
d
e
f
<<<
"1:2:3:4:5:6"
쉘은 read 명령 기간 동안 IFS 변수를 설정하고 read
$ IFS를 입력에 적용 하고 변수 이름에 값을 제공 하는 방법을 알고 있습니다.
이 명령은 비슷한 이야기이지만 다른 결과가 있습니다. HOME="hello" echo "$HOME"
명령이 시작 되기 전에 매개 변수 확장이 발생하므로 쉘에는 다음이 있습니다.
HOME="hello" echo "/home/username"
그런 다음 echo 명령을 실행하는 동안 $ HOME의 새 값이 전혀 사용되지 않습니다.
수행하려는 작업을 수행하려면 다음 중 하나를 선택하십시오.
# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'
또는
# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")
그러나 첫 번째 것을 선택하지 마십시오.
eval
솔루션을 피해야 하는 이유는 무엇 입니까?
환경 변수와 로컬 변수의 두 가지 범위가 있습니다. 환경 변수는 모든 프로세스 (참조에 유효한 setenv
, getenv
로컬 변수는이 쉘 세션 내에서 활성 상태). (명백한 차이점은 아닙니다 ...)
암시 적으로 env
(예와 같이) 환경을 수정 echo ...
하고 로컬 환경을 사용하므로 env
아무런 영향을 미치지 않습니다.
지역 변수를 수정하려면 다음과 같이 사용하십시오.
( HOME="foo" ; echo "$HOME" )
여기에서 괄호는이 과제의 범위를 정의합니다.
local
입니다.