프로세스의 환경 변수를 읽는 방법


43

Linux /proc/<pid>/environ는 업데이트되지 않습니다 (내가 이해하는 것처럼 파일에는 프로세스의 초기 환경이 포함되어 있음).

프로세스의 현재 환경을 어떻게 읽을 수 있습니까?

답변:


20

/proc/$pid/environ프로세스가 자체 환경을 변경하면 업데이트합니다. 프로그램의 환경은을 통해 정상적인 채널을 통해 볼 수 없습니다 : 그것은 조금 무의미이기 때문에 그러나 많은 프로그램은 자신의 환경을 변경 귀찮게하지 않습니다 /proc하고 ps, 심지어는없는 모든 유닉스 변종 기능의이 종류를 가지고 응용 프로그램을 의존하지 않도록, 그 위에.

커널에 관한 한, 환경 execve은 프로그램을 시작하는 시스템 호출 의 인수로만 나타납니다 . 리눅스는를 통해 메모리의 영역을 노출시키고 /proc, 일부 프로그램은이 영역을 업데이트하지만 다른 프로그램은 그렇지 않습니다. 특히, 어떤 쉘 도이 영역을 업데이트한다고 생각하지 않습니다. 면적이 고정 크기이므로 새 변수를 추가하거나 값의 길이를 변경할 수 없습니다.


따라서 효과적으로 프로세스의 * envp (환경 설정에 대한 포인터 배열)에 액세스 할 수있는 방법이 없습니다. @Gilles, 디버거를 연결하고 환경 설정에 대한 포인터 배열을 읽을 수 있는지 보여줄 수 있습니까?
Nikhil Mulley

2
@Nikhil 물론입니다. 그러나 PATH=foo쉘로 작성 한다고해서 쉘이 수정된다는 의미는 아닙니다 *envp. 일부 셸에서는 내부 데이터 구조 만 업데이트했으며 업데이트하는 외부 프로그램 실행 코드입니다 *envp. 봐 assign_in_env에서 variables.c예를 들어, bash는 소스입니다.
Gilles 'SO- 악마 그만'

9
@Gilles :이 답변은 오해의 소지가 있습니다 (-1). / proc / $$ / environ의 환경은 프로세스 스택에서 읽습니다. fs / proc / base.c를 참조하십시오. 이것이 초기 환경입니다. 업데이트되지 않으며 실제로는 업데이트 할 수 없습니다. libc setenv가 사용하는 환경은 힙에 할당되고 스택의 환경 내용으로 초기화됩니다. 프로세스가 libc를 호출 fork하면 libc는 sys_fork하위 프로세스에 힙 할당 환경을 사용하여 호출합니다.
조나단 벤-아브라함

7
@ JonathanBen-Avraham 셸에서 초기 환경이 업데이트되지 않은 것이 맞습니다. 그러나 해당 영역은 Linux에서만 읽을 수는 없지만 상태를보고하는 데 사용하는 프로그램을 발견했습니다 (상태 보고서 argv가 더 일반적이지만 둘 다 존재합니다).
Gilles 'SO- 악의를 멈춰라'

39

에서 프로세스 의 초기 환경을 읽을 수 있습니다 /proc/<pid>/environ.

프로세스 환경을 변경 하는 경우 환경을 읽으려면 프로세스의 기호 테이블이 있어야하고 ptrace시스템 호출 (예 :을 사용하여 gdb)을 사용 하여 전역 char **__environ변수 에서 환경을 읽으십시오 . 실행중인 Linux 프로세스에서 변수의 값을 얻는 다른 방법은 없습니다.

그게 답입니다. 이제 몇 가지 참고 사항이 있습니다.

위의 프로세스는 POSIX 호환 프로세스라고 가정합니다. 즉 프로세스가 Ref Spec에char **__environ 지정된 전역 변수 를 사용하여 환경을 관리합니다 .

프로세스의 초기 환경은 프로세스 스택의 고정 길이 버퍼에서 프로세스로 전달됩니다. (이 작업을 수행 일반적인 메커니즘입니다 linux//fs/exec.c:do_execve_common(...).) 버퍼의 크기가 더 이상 할 초기 환경에 필요한 크기보다, 기존 변수를 지우거나 스택 스매싱 않고 새로운 변수를 추가 할 수 없습니다 계산되지 않기 때문에. 따라서 프로세스 환경의 변경을 허용하는 합리적인 체계는 힙을 사용하는데, 임의 크기의 메모리를 할당하고 해제 할 수 있습니다. 이는 GNU libc( glibc) 가 정확히하는 역할입니다.

프로세스가을 사용하는 경우 glibcPOSIX와 호환 __environ되며 glibc//posix/environ.cGlibc 에서 선언되어 프로세스의 힙에서 가져온 __environ메모리에 대한 포인터로 초기화 malloc한 다음 스택의 초기 환경을이 힙 영역으로 복사합니다. 프로세스가 setenv함수를 사용할 때마다 glibca 는 새 값 또는 변수를 수용하도록 가리키는 realloc영역의 크기를 조정합니다 __environ. 으로 glibc 소스 코드를 다운로드 할 수 있습니다 git clone git://sourceware.org/git/glibc.git glibc. 메커니즘을 실제로 이해하려면 Hurd 코드도 읽어야합니다 hurd//init/init.c:frob_kernel_process()(git clone git : //git.sv.gnu.org/hurd/hurd.git hurd).

새로운 프로세스는 경우 이제 fork에드 후속없이, exec스택을 덮어 쓰기, 다음 인수 및 환경 복사 마법에서 이루어집니다 linux//kernel/fork.c:do_fork(...)경우, copy_process루틴 호출을 dup_task_struct호출하여 새로운 프로세스의 스택을 할당 alloc_thread_info_node, 전화 setup_thread_stack( linux//include/linux/sched.h새로운 프로세스)를 사용 alloc_thread_info_node.

마지막으로 POSIX __environ규칙은 사용자 공간 규칙입니다. Linux 커널에서는 아무 것도 연결되어 있지 않습니다. 전역 을 사용 glibc하거나 사용하지 않고 사용자 공간 프로그램을 작성한 __environ다음 원하는 환경 변수를 관리 할 수 ​​있습니다. 아무도 당신을이 일로 체포하지는 않지만 자신의 환경 관리 기능 ( setenv/ getenv)과 자신의 래퍼를 작성 sys_exec해야 할 것이며 아무도 환경의 변화를 어디에서했는지 추측 할 수 없을 것입니다.


파일의 대부분이 /proc/[pid]/이상한 인코딩을 가진 것으로 보입니다 (다른 사람이 무엇을, 왜 알 수 있는지). 나를 cat environ위해 환경 변수를 읽기 어려운 형식으로 인쇄하기 만하면 됩니다. cat environ | strings나를 위해 이것을 해결했습니다.
retrohacker

@retrohacker 이것은보다 강력한 솔루션을 제공합니다 : askubuntu.com/questions/978711/…
Frank Kusters

20

프로세스가 환경 변수를 획득 / 삭제할 때 업데이트됩니다. environ/ proc 파일 시스템의 프로세스 디렉토리에 프로세스에 대해 파일이 업데이트되지 않았다는 참조가 있습니까?

xargs --null --max-args=1 echo < /proc/self/environ

또는

xargs --null --max-args=1 echo < /proc/<pid>/environ

또는

ps e -p <pid>

위는 프로세스의 환경 변수를 ps출력 형식으로 인쇄하며 , 환경 변수를 목록으로 보려면 텍스트 처리 (구문 분석 / 필터링)가 필요합니다.

솔라리스 (요청하지는 않지만 참조를 위해 여기에 게시합니다) :

/usr/ucb/ps -wwwe <pid>

또는

pargs -e <pid> 

편집 : / proc / pid / environ이 업데이트되지 않았습니다! 나는 정정되었다. 확인 과정은 다음과 같습니다. 그러나 프로세스가 분기되는 하위 프로세스는 프로세스 환경 변수를 상속하며 각각의 / proc / self / environ 파일에 표시됩니다. (문자열 사용)

쉘에서 : xargs는 자식 프로세스이므로 환경 변수를 상속하고 /proc/self/environ파일 에도 반영 됩니다.

[centos@centos t]$ printenv  | grep MASK
[centos@centos t]$ export MASK=NIKHIL
[centos@centos t]$ printenv  | grep MASK
MASK=NIKHIL
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ  | grep MASK
MASK=NIKHIL
[centos@centos t]$ unset MASK
[centos@centos t]$ printenv  | grep MASK
[centos@centos t]$ xargs --null --max-args=1 echo < /proc/self/environ  | grep MASK
[centos@centos t]$

터미널 / 세션이 환경 변수가 설정된 쉘의 하위 프로세스가 아닌 다른 세션에서 확인하십시오.

동일한 호스트의 다른 터미널 / 세션에서 확인 :

terminal1 : : printenv는 분기되어 bash의 자식 프로세스이므로 자체 환경 파일을 읽습니다.

[centos@centos t]$ echo $$
2610
[centos@centos t]$ export SPIDEY=NIKHIL
[centos@centos t]$ printenv | grep SPIDEY
SPIDEY=NIKHIL
[centos@centos t]$ 

terminal2 : 동일한 호스트에서-위 변수가 설정된 동일한 쉘에서 시작하지 말고 터미널을 개별적으로 시작하십시오.

[centos@centos ~]$ echo $$
4436
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/self/environ | grep -i spidey
[centos@centos ~]$ strings -f /proc/2610/environ | grep -i spidey
[centos@centos ~]$ xargs --null --max-args=1 echo < /proc/2610/environ | grep -i spidey
[centos@centos ~]$ 

1
내가 할 export foo=bar하나의 bash는 세션 (PID XXXX)에, 다음 할 cat /proc/xxxx/environ | tr \\0 \\n다른 배쉬의 세션에서 나는 볼 수 없습니다 foo.

쉘에서 동일한 프로세스를 확인하는 예제로 위의 답변을 업데이트했습니다.
Nikhil Mulley

당신이 올바른지. 나는 정정되었다. 감사. 이제 사용자 프로세스 그룹에서 다른 프로세스의 환경 변수를 확인하려면 설명서를 읽어야합니다.
Nikhil Mulley

1
한 가지 더 : 나는 gdb pid에 환경을 연결하려고 시도 했지만 여전히 참조가 없습니다. 메모리의 환경 변수 블록은 변경이있을 때마다 재 할당되고 proc 파일 시스템의 자체 프로세스 환경 파일에 반영되지 않지만 자식 프로세스에 의해 상속 될 수 있습니다. 즉, 포크가 발생할 때 본질적인 세부 사항을 더 쉽게 알 수 있으며 자식 프로세스가 환경 변수를 그대로 복사하는 방법은 무엇입니까?
Nikhil Mulley

@Gilles가 이것에 그의 토치 라이트를 던지기를 바랍니다 .. :-)
Nikhil Mulley

7

다음은 저자의 실제 의도와 관련이 없지만 실제로 "읽기"를 원한다면 /proc/<pid>/environ시도해보십시오.

strings /proc/<pid>/environ

cat그것 보다 낫다 .


1
일에 대한 strings. 간단하게 유지하십시오.
Ed Randall

@EdRandall에 동의하십시오 xargs --null.
Per Lundberg

"파일"은 널로 종료됩니다. 널을 줄 바꾸기로 바꾸고 일반적인 도구를 사용하여 일반적인 도구를 다시 사용하십시오.tr '\0' '\n' < /proc/$$/environ | ...
Thor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.