env 출력에서 ​​볼 수있는 변수를 인쇄 할 수없는 이유는 무엇입니까?


9

한 쉘 인스턴스의 환경 변수를 다른 쉘 인스턴스에서 설정하는 데 관심이 있습니다. 그래서 연구를하기로 결정했습니다. 읽은 후 질문 에 대한 나는 그것을 테스트하기로 결정했다.

나는 두 개의 쉘 A와 B (PID 420)를 생성했으며 둘 다 실행 중 zsh입니다. 쉘 AI에서 다음을 실행했습니다.

sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach

셸 B에서 실행 env하면 변수 FOO가 실제로 bar 값으로 설정되어 있음을 알 수 있습니다. 이것은 쉘 B의 환경에서 FOO가 성공적으로 초기화되었다고 생각합니다. 그러나 FOO를 인쇄하려고하면 빈 줄이 설정되어 있지 않음을 나타냅니다. 나에게는 모순이있는 것처럼 느낍니다.

이것은 내 자신의 Arch GNU / Linux 시스템과 Ubuntu VM 모두에서 테스트되었습니다. 또한 bash변수가 env에 표시되지 않은 곳 에서도 이것을 테스트했습니다 . 이것은 나에게 실망 스럽지만 쉘이 생성시 환경의 사본을 캐시하고 그 링크 만 사용하면 (연관된 질문 중 하나에서 제안 된) 의미가 있습니다. 이것은 여전히 zsh변수를 볼 수있는 이유에 대한 답변이 아닙니다 .

출력이 왜 echo $FOO비어 있습니까?


편집하다

의견을 입력 한 후 조금 더 테스트하기로 결정했습니다. 결과는 아래 표에서 확인할 수 있습니다. 첫 번째 열에는 FOO변수가 주입 된 쉘이 있습니다. 첫 번째 행에는 그 아래에 출력을 볼 수있는 명령이 포함됩니다. 변수 FOO는 다음을 사용하여 주입되었습니다 sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'. zsh :에 특정한 명령 zsh -c '...'은 bash를 사용하여 테스트되었습니다. 결과는 동일했고 결과는 간결하게 생략되었습니다.

아치 GNU / 리눅스, zsh 5.3.1, bash 4.4.12 (1)

|      |  env | grep FOO  | echo $FOO |  zsh -c 'env | grep FOO'  |  zsh -c 'echo $FOO'  |         After export FOO          |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh  |  FOO=bar         |           | FOO=bar                   | bar                  | No Change                         |
| bash |                  | bar       |                           |                      | Value of FOO visible in all tests |

우분투 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)

|      |  env | grep FOO  | echo $FOO |  zsh -c 'env | grep FOO'  |  zsh -c 'echo $FOO'  |         After export FOO          |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh  |  FOO=bar         |           | FOO=bar                   | bar                  | No Change                         |
| bash |                  | bar       |                           |                      | Value of FOO visible in all tests |

위의 결과는 분포에 무관심하다는 것을 암시하는 것 같습니다. 이것은 더 이상 말하지 않습니다 zshbash다른 변수의 핸들을 설정. 또한 export FOO셸에 따라이 컨텍스트에서 동작이 매우 다릅니다. 이 테스트가 다른 사람에게 분명한 것이 될 수 있기를 바랍니다.


zsh -c 'echo $FOO'대신 작은 따옴표를 사용 하면 어떻게됩니까 ? 그때 볼 수 있습니까?
user1934428

올바른 값은 새 하위 쉘에서 인쇄됩니다 (bash 하위에서도 테스트 됨). 자녀가 환경을 물려받을 수있는 환경은 분명히 지속되지만 부모는 왜 그것을 존중하지 않습니까?
rlf

3
그것이 내가 생각했던 거죠. 쉘은 변수의 심볼 테이블을 가지고 있다고 생각하는데, 그중 일부는 "내 보낸"으로 표시됩니다. 즉, 서브 쉘을 열면 하위 프로세스 환경에 배치됩니다. 처음에는 (쉘이 시작될 때) 당시 환경의 변수가 기호 테이블에 복사됩니다 (물론 "내 보낸"변수). 환경을 변경하면 셸은 기호 테이블을 업데이트한다는 사실을 알지 못하지만 자식 프로세스 (예 env:)는 수정 된 환경을 봅니다.
user1934428

2
zsh 5.1.1 및 bash 4.3.48 (1)을 사용하여 Ubuntu 16.04에서 테스트 zsh했으며 GDB에서 환경 변수를 설정하면 셸 변수로 표시되지 않지만 자식 프로세스에 전달됩니다 ( 당신은 하나 설정하는 동안,)를 관찰 bash 않은 쉘 변수로 볼 수 있도록를하지만 않습니다 하지 그것은 자식 프로세스에 전달하는 원인! zsh와 bash는 환경 관리가 아닌 변수를 추적하는 zsh와 (서브 쉘이 아닌) 자식을 시작할 때 살균하는 환경에 모든 것을 저장하는 bash와 함께 변수 관리를 위해 다른 전략을 사용하는 것처럼 보입니다.
Eliah Kagan

@EliahKagan, 흥미로운; 답변으로 게시해야합니다. 당신이 실행하는 경우이 차이가 있는지 또한 궁금 export FOO에서 bash?
와일드 카드

답변:


2

대부분의 쉘은 getenv()/ setenv()/ putenv()API를 사용하지 않습니다 .

시작시 각 환경 변수에 대한 쉘 변수를 작성합니다. 그것들은 변수가 익스포트되는지, 읽기 전용인지와 같은 다른 정보를 전달할 필요가있는 내부 구조에 저장 될 것입니다. 그것들은 libc를 사용할 수 없습니다 environ.

마찬가지로, 그 이유는 그들이 사용하지 않는 execlp(), execvp()명령을 실행할 수 있지만, 전화 execve()컴퓨팅 직접 시스템 호출 envp[]들이 보낸 변수의리스트에 기초하여 배열.

따라서에서 gdb셸 내부 변수 테이블에 항목을 추가하거나 export VAR=value해당 테이블을 자체적으로 업데이트 하는 코드를 해석하는 올바른 함수를 호출해야 할 수도 있습니다.

왜 전화를 걸었 을 때 bashzsh전화를 걸었 setenv()을 때 차이 gdb가 나는지 setenv()에 대해서는 쉘 초기화 전에 전화를 걸었 기 때문 main()입니다.

당신은 알 수 bash'들 main()입니다 int main(int argc, char* argv[], char* envp[])(그리고 bash그 ENV가에 바르에서 변수를 매핑 envp[]) 동안 zsh'이다이야 int main(int argc, char* argv[])zsh에서 변수를 가져옵니다 environ대신. setenv()내부에서 수정 environ하지만 수정할 수는 없습니다 envp[](포인터가 가리키는 문자열뿐만 아니라 여러 시스템에서 읽기 전용).

쉘이 읽은 후에 어떤 경우에는 environ시작할 때, 사용하는 것은 setenv()더 이상 사용 쉘 등의 효과가있을 것 environ(또는 getenv()) 이후.

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