Unix에서 다른 프로세스의 환경 변수를 변경하는 방법이 있습니까?


105

Unix에서 한 프로세스가 다른 프로세스의 환경 변수를 변경할 수있는 방법이 있습니까 (모두 동일한 사용자에 의해 실행되고 있다고 가정)? 일반적인 해결책이 가장 좋지만 그렇지 않다면 하나가 다른 하나의 자식 인 특정 경우는 어떻습니까?

편집 : gdb를 통해 어떻습니까?


이것은 추한 것 이상으로 나를 때립니다. 해결하고 싶은 실제 문제는 무엇입니까?
Jens 2012 년

1
예 : UI에 의해 시작된 모든 새 앱이 가져 오도록 환경 변수를 정의하고 싶습니다. 시작 스크립트 및 RE-LOGIN 중 하나에서 변수를 정의하는 것 외에는 어떤 방법도 모릅니다. 그러나 다시 로그인하지 않고 새 앱이 UI에서 로그 아웃하지 않고 가져올 수 있도록 현재 세션의 변수를 정의하고 싶습니다.
AlikElzin-kilaka

답변:


142

gdb를 통해 :

(gdb) attach process_id

(gdb) call putenv ("env_var_name=env_var_value")

(gdb) detach

이것은 매우 끔찍한 해킹이며 물론 디버깅 시나리오의 컨텍스트에서만 수행해야합니다.


8
따라서 이것은 GDB처럼 프로세스에 연결 한 다음 분리하면 실제로 프로세스의 환경을 변경할 수 있음을 의미합니다. 이것만을 수행하는 프로그램을 작성하는 것이 가능할 것 같습니다.
슬픔

3
"이렇게 만하는 프로그램을 작성할 수있을 것 같다."과연 .. 그렇다.
L̳o̳̳n̳̳g̳̳p̳o̳̳k̳̳e̳̳

2
cygwin을 사용하여 컴파일되지 않은 프로세스의 경우 cygwin을 사용하는 Windows에서도 작동합니다!
Juan Carlos Muñoz

11
이는 프로세스가 이전 getenv 이후 값을 영구적으로 캐시하지 않은 경우에만 작동합니다.
An̲̳̳drew

1
ptrace: Operation not permitted
gerrit 2014.03.22

22

기술적으로 할 수는 있지만 (다른 답변 참조) 도움이되지 않을 수 있습니다.

대부분의 프로그램은 시작 후에 env vars를 외부에서 변경할 수 없다고 예상하므로 대부분은 시작시 관심있는 vars를 읽고이를 기반으로 초기화합니다. 따라서 나중에 변경해도 프로그램이 다시 읽지 않기 때문에 차이가 없습니다.

이것을 구체적인 문제로 게시했다면 아마도 다른 접근 방식을 취해야 할 것입니다. 호기심에서 나온 것이라면 : 좋은 질문입니다 :-).


1
유용한 가장 일반적인 사용 사례는 새 터미널이 새 변수를 사용하도록하려는 데스크톱 환경과 같이 자식 프로세스가 새 환경 변수를 상속하도록 만드는 것입니다.
Hjulle

13

실질적으로 아닙니다. 충분한 권한 (루트 또는 그 주변)이 있고 / dev / kmem (커널 메모리) 주위를 찌르고 프로세스의 환경을 변경했으며 프로세스가 실제로 나중에 환경 변수를 다시 참조했는지 (즉, 프로세스 이미 env var의 사본을 가져 오지 않았고 해당 사본 만 사용하지 않았습니다.) 운이 좋고 영리하고 바람이 올바른 방향으로 불고 달의 위상이 정확하다면 아마도 당신은 뭔가를 얻을 수 있습니다.


2
나는 답을 얻지 못했다.
AlikElzin-kilaka

@kilaka : 핵심 단어는 두 번째 단어입니다 . 아니오 . 나머지 대답은 루트 권한이 있거나 디버거를 실행중인 경우 수행 할 수 있지만 모든 실제적인 목적을 위해 대답은 No 입니다.
Jonathan Leffler

쉘 스크립트가 실행 중입니다. 셸 스크립트의 부모 프로세스에서 환경을 변경하려는 경우 ... 셸 스크립트가 부모 프로세스에서 시작 gdb되고 변경을 수행하도록 스크립팅되며 부모 프로세스를 중단하지 않고 작동합니다. 좋습니다. 아마 할 수는 있지만 일상적으로 할 일은 아닙니다. 따라서 실질적인 목적을 위해 대답은 아니요로 유지 됩니다. 나머지 답변은 이론적으로 가능하고 다소 비현실적으로 가능한 대안을 다룹니다.
Jonathan Leffler 2012

7

Jerry Peek 인용 :

늙은 개에게 새로운 속임수를 가르 칠 수 없습니다.

할 수있는 유일한 방법은 시작 하기 전에 자식 프로세스의 환경 변수를 변경하는 것 입니다. 죄송합니다. 부모 환경의 복사본을 가져옵니다.

자세한 내용은 http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm 을 참조하십시오.

/ proc 사용에 대한 답변에 대한 의견입니다. 리눅스에서는 / proc가 지원되지만 작동하지 않으며, 루트 사용자라도 파일을 변경할 수 없습니다 . 절대적으로 읽기 전용입니다./proc/${pid}/environ


여전히 질문을 남깁니다. env var 값은 실제로 어디에 저장됩니까? 커널에 의해 수행됩니까? 아니면 쉘이 값을 저장하고 / proc / <pid> / environ이 값을 가져 옵니까?
oliver

이것은 구현 세부 사항이며 (별도의) 좋은 질문 일 수 있습니다. 나는 모든 UNIX가 스토리지에 대해 고유 한 방식을 사용한다고 생각하지만 모두 위에서 설명한 동작을 공유하며 이는 사양의 일부입니다.
Davide

7

그렇게하는 다소 인위적인 방법을 생각할 수 있으며 임의의 프로세스에서는 작동하지 않습니다.

'char * getenv'를 구현하는 자체 공유 라이브러리를 작성한다고 가정합니다. 그런 다음 'LD_PRELOAD'또는 'LD_LIBRARY_PATH'환경을 설정합니다. vars를 사용하여 두 프로세스가 모두 미리로드 된 공유 라이브러리로 실행되도록합니다.

이렇게하면 기본적으로 'getenv'함수의 코드를 제어 할 수 있습니다. 그런 다음 모든 종류의 불쾌한 트릭을 할 수 있습니다. 'getenv'는 env vars의 대체 값에 대해 외부 구성 파일 또는 SHM 세그먼트를 참조 할 수 있습니다. 또는 요청 된 값에 대해 regexp 검색 / 대체를 수행 할 수 있습니다. 아니면 ...

동적 링커 (ld-linux.so)를 다시 작성하지 않고 임의의 실행 프로세스 (루트 인 경우에도)에 대해이를 수행하는 쉬운 방법을 생각할 수 없습니다.


이것은 가능해야합니다. var = value 쌍에 대한 작은 gdbm 데이터베이스를 가질 수 있습니다. I은 malloc에 대한 비슷한 일이 stromberg.dnsalias.org/~strombrg/malloc-wrapper
dstromberg

그래도이 방법은 미리 생각 해봐야한다고 생각합니다. 또한 실수로 너무 많은 프로세스에 적용하지 않도록주의해야합니다.
dstromberg

3

또는 새 프로세스에 대한 구성 파일을 업데이트하도록 프로세스를 가져온 다음 다음 중 하나를 수행하십시오.

  • 새 프로세스에서 kill -HUP를 수행하여 업데이트 된 구성 파일을 다시 읽거나
  • 프로세스가 때때로 업데이트를 위해 구성 파일을 확인하도록하십시오. 변경 사항이 발견되면 구성 파일을 다시 읽으십시오.

2

내가 아는 한 멀지 않습니다. 실제로 IPC 메서드 (공유 메모리, 세마포어, 소켓 등) 중 하나를 호출하는 한 프로세스에서 다른 프로세스로 통신하려고합니다. 이러한 방법 중 하나를 사용하여 데이터를 수신하면 환경 변수를 설정하거나 다른 작업을보다 직접 수행 할 수 있습니다.


1

유닉스가 / proc 파일 시스템을 지원한다면 env를 읽는 것은 쉬운 일이 아닙니다. 환경, 명령 줄, 그리고 당신이 소유 한 모든 프로세스의 다른 많은 속성을 읽을 수 있습니다. 변경 ... 글쎄, 방법을 생각할 수 있지만 나쁜 생각입니다.

좀 더 일반적인 경우 ... 모르겠습니다.하지만 휴대용 답이 있을지 의심 스럽습니다.

(편집 됨 : 내 원래 대답은 OP가 환경을 변경하지 않고 읽기를 원한다고 가정했습니다)


죄송합니다. 내 대답을 편집했습니다. 나는 그가 환경을 변경하는 것이 아니라 읽기를 원한다고 가정했습니다.
Mike G.

1
나를 매달리지 마십시오. 당신의 나쁜 생각은 무엇입니까?
raldi

Linux에서는 소유 한 다른 프로세스에 대해 / proc / <pid> / mem 읽기-쓰기를 열 수 있다고 믿습니다.하지만 확실하지 않습니다. 시도하고 실제로 환경을 망치는 것은 확실히 나쁜 생각입니다. 그래서 나는 당신이 그것을 시도하는 것을 제안하지 않습니다 ...
Mike G.

1

UNIX는 프로세스 간 통신으로 가득 차 있습니다. 대상 인스턴스에 일부가 있는지 확인하십시오. Dbus는 "데스크탑"IPC의 표준이되고 있습니다.

awesome-client 를 사용하여 Awesome 창 관리자 내부의 환경 변수 를 lua 코드의 Dbus "발신자"로 변경합니다.


1

직접적인 대답은 아니지만 ... Raymond Chen은이 문제에 대해 [Windows 기반] 근거를 가지고있었습니다 .

... 확실히 지원되지 않는 방법이나 디버거의 도움으로 작동하는 방법이 있지만, 다른 프로세스의 명령 줄에 대한 프로그래밍 방식 액세스를 지원하는 방법은 없습니다. 최소한 커널에서 제공하는 것은 없습니다. ...

필요하지 않은 정보를 추적하지 않는 원칙의 결과는 없습니다. 커널은 다른 프로세스의 명령 줄을 얻을 필요가 없습니다. CreateProcess함수에 전달 된 명령 줄 GetCommandLine을 가져 와서 함수가 검색 할 수 있는 위치에서 시작되는 프로세스의 주소 공간에 복사 합니다. 프로세스가 자체 명령 줄에 액세스 할 수있게되면 커널의 책임이 수행됩니다.

명령 줄이 프로세스의 주소 공간에 복사되기 때문에 프로세스는 명령 줄이있는 메모리에 쓰고 수정할 수도 있습니다. 이런 일이 발생하면 원래 명령 줄이 영원히 손실됩니다. 알려진 유일한 사본이 덮어 써졌습니다.

즉, 그러한 커널 기능은

  • 구현하기 어렵다
  • 잠재적으로 보안 문제

그러나 가장 가능성이 높은 이유는 단순히 그러한 시설에 대한 사용 사례가 제한되어 있기 때문입니다.


1

보인다 하는 putenv가 지금은 작동하지 않지만 에서는 setenv는 않습니다. 나는 성공하지 못한 현재 쉘에서 변수를 설정하려고 시도하면서 받아 들여지는 대답을 테스트하고 있었다.

$] sudo gdb -p $$
(gdb) call putenv("TEST=1234")
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x0
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=

작동 방식 :

$] sudo gdb -p $$
(gdb) call (int) setenv("TEST", "1234", 1)
$1 = 0
(gdb) call (char*) getenv("TEST")
$2 = 0x55f19ff5edc0 "1234"
(gdb) detach
(gdb) quit
$] echo "TEST=$TEST"
TEST=1234
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.