쉘 변수의 범위가 명확하지 않다는 문제가 발생했습니다.
작업을 수행하기 위해 $GEM_HOME
값을 사용하는 Ruby 명령 인 bundle install
를 사용합니다. ,하지만 export GEM_HOME=/some/path
에서처럼 export
를 사용할 때까지 명령은 해당 값을 무시했습니다.
이로 인해 변수가 “전역”( 환경 변수 라고도 함)이 어떻게 든 “글로벌”이라는 것을 읽었지만 그것이 무엇을 의미하는지 이해하십시오. 프로그래밍에서 전역에 대해 알고 있지만 개별 프로그램에는 적용되지 않습니다.
또한 이러한 변수 설정이 현재 셸 세션에만 적용된다는 점을 감안할 때 데몬 화 된 프로세스에 대해 어떻게 설정해야합니까?
셸 변수는 어떤 범위를 가질 수 있습니까?
답변
프로세스는 트리로 구성됩니다. 모든 프로세스에는 init
를 제외하고 PID
는 항상 1이며 부모가 없습니다.
새 프로세스 생성은 일반적으로 fork
/ execv
시스템 호출. 여기서 하위 프로세스의 환경은 상위 프로세스의 복사 입니다.
셸에서 환경에 변수를 넣으려면 해당 변수를 export
해야 모든 하위 항목이 재귀 적으로 볼 수 있습니다. 그러나 자식이 변수의 값을 변경하면 변경된 값은 해당 변수와 변경된 이후 에 생성 된 모든 프로세스 (이전과 같이 사본 이 됨)에만 표시됩니다.
예를 들어 login
에서 수행 한 것처럼 하위 프로세스가 환경을 변경할 수 있다는 점도 고려하십시오. 예.
댓글
Answer
At 최소한 ksh
및 bash
에서 변수는 3 개 범위, 2 개의 나머지 모든 답변이 현재 말하고있는 것처럼
In 내 보낸 (예 : 환경) 변수 및 셸 내보내기되지 않은 변수 범위 외에도 함수 지역 변수에 대해 세 번째로 좁은 범위가 있습니다.
typeset
토큰은 선언 된 함수 내부와 거기에서 호출 된 (sub) 함수에서만 볼 수 있습니다.
이 ksh
/ bash
코드 :
# Create a shell script named /tmp/show that displays the scoped variables values. echo "echo [$environment] [$shell] [$local]" > /tmp/show chmod +x /tmp/show # Function local variable declaration function f { typeset local=three echo "in function": . /tmp/show } # Global variable declaration export environment=one # Unexported (i.e. local) variable declaration shell=two # Call the function that creates a function local variable and # display all three variable values from inside the function f # Display the three values from outside the function echo "in shell": . /tmp/show # Display the same values from a subshell echo "in subshell": /tmp/show # Display the same values from a disconnected shell (simulated here by a clean environment start) echo "in other shell" env -i /tmp/show
이 출력을 생성합니다.
in function: [one] [two] [three] in shell: [one] [two] [] in subshell: [one] [] [] in other shell [] [] []
보시다시피 내 보낸 변수는 처음 세 위치에서 표시되고 내 보내지 않은 변수는 현재 셸 외부에 표시되지 않으며 함수 로컬 변수에는 함수 자체 외부에 값이 없습니다. 마지막 테스트에서는 값이 전혀 표시되지 않습니다. 이는 내 보낸 변수가 쉘간에 공유되지 않기 때문입니다. 즉, 상속 만 가능하고 상속 된 값은 나중에 상위 쉘에 의해 영향을받을 수 없기 때문입니다.
후자의 동작은 모든 프로세스에서 완전히 전역적이고 공유되는 시스템 변수를 사용할 수있는 Windows 동작과는 상당히 다릅니다.
답변
그들은 프로세스별로 범위가 지정됩니다.
다른 응답자들은 쉘 변수 범위가 프로세스에 관한 것이라는 것을 이해하는 데 도움이되었습니다. 및 그 하위 항목 .
명령 줄에 ls
와 같은 명령을 입력하면 실제로 프로세스를 분기하여 ls
프로그램을 실행합니다. 새 프로세스에는 셸이 부모로 있습니다.
모든 프로세스는 자체 “로컬”변수를 가질 수 있습니다. 하위 프로세스에 전달되지 않습니다. “환경”변수를 설정할 수도 있습니다. export
를 사용하면 환경 변수가 생성됩니다. 경우, 관련없는 프로세스 (원본의 동료)는 변수를 볼 수 없습니다. esses see.
A라고 부르는 bash 쉘이 있다고 가정합니다. bash
를 입력합니다. , B라고 부르는 자식 프로세스 bash 셸을 만듭니다. A에서 export
를 호출 한 모든 항목은 여전히 B로 설정됩니다.
이제, B에서는 FOO=b
라고 말합니다. 다음 두 가지 중 하나가 발생합니다.
- B가 (A로부터)
FOO
라는 환경 변수를받지 못한 경우 로컬 변수를 생성합니다. B의 하위 항목은 해당 정보를 얻지 못합니다 (B가export
를 호출하지 않는 한). - B가 인 경우 A로부터
FOO
라는 환경 변수를 수신하면 자체를 위해 수정하고 그 후에 갈라진 아이들 . B의 자식은 B가 할당 한 값을 볼 수 있습니다. 그러나 A에는 전혀 영향을주지 않습니다.
다음은 빠른 데모입니다. .
FOO=a # set "local" environment variable echo $FOO # "a" bash # forks a child process for the new shell echo $FOO # not set exit # return to original shell echo $FOO # still "a" export FOO # make FOO an environment variable bash # fork a new "child" shell echo $FOO # outputs "a" FOO=b # modifies environment (not local) variable bash # fork "grandchild" shell echo $FOO # outputs "b" exit # back to child shell exit # back to original shell echo $FOO # outputs "a"
이 모든 것이 내 원래 문제를 설명합니다. 쉘에 GEM_HOME
를 설정했지만 bundle install
, 하위 프로세스를 생성했습니다. export
를 사용하지 않았기 때문에 하위 프로세스가 쉘의 GEM_HOME
.
내보내기 취소
export -n FOO
.
export FOO=a # Set environment variable bash # fork a shell echo $FOO # outputs "a" export -n FOO # remove environment var for children bash # fork a shell echo $FOO # Not set exit # back up a level echo $FOO # outputs "a" - still a local variable
댓글
- 말할 때 ” 자체 및 하위 항목을 위해 수정합니다. ” 수정 후 에 생성 된 하위 항목 만 명시해야합니다. 수정 된 값이 표시됩니다.
- @enzotib-좋은 지적입니다. 업데이트되었습니다.
답변
내보내기에 대해 찾을 수있는 가장 좋은 설명은 다음과 같습니다.
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
서브 쉘 또는 하위 쉘 내에 설정된 변수는 다음 사용자에게만 표시됩니다. 정의 된 서브 쉘. 내 보낸 변수는 실제로 환경 변수로 만들어집니다. 따라서 bundle install
는 iv id = “42dce32f9e로 만들어지지 않는 한 $GEM_HOME
를 볼 수없는 자체 셸을 실행합니다. “>
변수 (일명 내보냄)
여기에서 변수 범위에 대한 설명서를 볼 수 있습니다.
http://www.tldp.org/LDP/abs/html/subshells.html
댓글
- 아, 그래서 ” 환경 변수 ” for
FOO=bar
;export
로 만들었습니다. 그에 따라 질문이 수정되었습니다. - 추가 한 링크를 살펴보세요.
답변
예상대로 변수 범위의 계층 구조가 있습니다.
환경
가장 바깥 쪽 범위는 환경입니다. 이것이 유일한 범위입니다. 운영 체제에 의해 관리되므로 모든 프로세스에 대해 존재하도록 보장됩니다. 프로세스가 시작되면 부모의 환경을 복사 한 후 둘이 독립적이됩니다. 자식의 환경을 수정해도 부모의 환경은 바뀌지 않으며 부모의 환경을 수정해도 기존 자식의 환경은 바뀌지 않습니다.
쉘 변수
쉘에는 고유 한 변수 개념이 있습니다. 이것이 약간 혼란스러워지기 시작하는 부분입니다.
셸의 변수에 값을 할당하고 해당 변수가 환경에 이미 존재하면 환경 변수가 새 값을받습니다. 그러나 변수가 아직 환경에 없으면 shell 변수가됩니다. Ruby 변수가 Ruby 스크립트 내에서만 존재하는 것과 유사하게 쉘 변수는 쉘 프로세스 내에서만 존재합니다. 자식 프로세스에 상속되지 않습니다.
여기에서 export
키워드가 작동합니다. 셸 변수를 셸 프로세스의 환경에 복사하여 자식 프로세스가 상속 할 수 있도록합니다.
지역 변수
지역 변수는이를 포함하는 코드 블록으로 범위가 지정된 셸 변수입니다. typeset
키워드 (휴대용) 또는 local
또는 declare
(배시 ). 다른 쉘 변수와 마찬가지로 지역 변수는 자식 프로세스에 상속되지 않습니다. 또한 지역 변수는 내보낼 수 없습니다.
FOO=bar
라고 말하면 현재 셸 프로세스의 값을 설정합니다. 그런 다음 (bundle install
)와 같은 프로그램을 실행하면 하위 프로세스가 생성되어 ‘FOO
. 그러나 내가export FOO=bar
라고 말했다면 하위 프로세스 (및 그 하위 프로세스)가 액세스 할 수 있습니다 . 그 중 하나는export FOO=buzz
를 호출하여 하위 항목의 값을 변경하거나FOO=buzz
를 호출하여 자신의 값만 변경할 수 있습니다. . 그게 맞습니까?