Есть ли в Unix способ, которым один процесс может изменять переменные среды другого (при условии, что все они запускаются одним и тем же пользователем)? Лучше всего было бы общее решение, но если нет, как насчет конкретного случая, когда один является потомком другого?
Обновлено: как насчет через GDB?
Пример: я хотел бы определить переменную среды, чтобы каждое новое приложение, запускаемое пользовательским интерфейсом, получало ее. Я не знаю ни одного метода, кроме определения переменных в одном из сценариев запуска и RE-LOGIN. Однако я бы хотел не повторно входить в систему, а просто определить переменные в текущем сеансе, чтобы новые приложения получали их - без выхода из пользовательского интерфейса.
Если ваш unix поддерживает файловую систему / proc, то ПРОЧИТАТЬ env тривиально - таким образом вы можете читать среду, командную строку и многие другие атрибуты любого процесса, которым вы владеете. Изменить это ... Ну, я могу придумать способ, но это ПЛОХАЯ идея.
Более общий случай ... Я не знаю, но сомневаюсь, что есть переносимый ответ.
(Отредактировано: мой первоначальный ответ предполагал, что OP хочет ПРОЧИТАТЬ env, а не изменять его)
Ой, отредактировал свой ответ - я предполагал, что он хочет прочитать env, а не изменять его.
Не оставляй меня висеть. Какая у тебя плохая идея?
Я считаю, что в Linux вы МОЖЕТЕ открыть / proc / <pid> / mem для чтения и записи для другого процесса, которым вы владеете ... Я не уверен. Пытаться и на самом деле возиться с окружающей средой ОПРЕДЕЛЕННО будет плохой идеей. Так что я не предлагаю вам попробовать ...
Цитата Джерри Пика:
You can't teach an old dog new tricks.
Единственное, что вы можете сделать, это изменить переменную окружения запускающего его дочернего процесса до: он получает копию родительского окружения, извините.
Подробнее см. http://www.unix.com.ua/orelly/unix/upt/ch06_02.htm.
Просто комментарий к ответу об использовании / proc. Под linux / proc поддерживается, но это не работает, вы не могу изменяете файл /proc/${pid}/environ
, даже если вы root: он доступен только для чтения абсолютно.
Остается вопрос: где на самом деле хранятся значения env var? Это делает ядро? Или оболочка хранит значения, а / proc / <pid> / Environment получает их оттуда?
Это деталь реализации, и это может быть (отдельный) хороший вопрос. Я думаю, что каждая UNIX использует свой собственный способ хранения, но все они разделяют поведение, описанное выше, что является частью спецификаций.
Насколько я знаю, нет. На самом деле вы пытаетесь общаться от одного процесса к другому, который вызывает один из методов IPC (общая память, семафоры, сокеты и т. д.). Получив данные одним из этих методов, вы можете затем установить переменные среды или выполнить другие действия более напрямую.
Или попросите свой процесс обновить файл конфигурации для нового процесса, а затем либо:
Я мог бы придумать довольно надуманный способ сделать это, и он не будет работать для произвольных процессов.
Предположим, вы пишете свою собственную общую библиотеку, которая реализует char * getenv. Затем вы настраиваете окружение LD_PRELOAD или LD_LIBRARY_PATH. vars, чтобы оба процесса запускались с предварительно загруженной общей библиотекой.
Таким образом, у вас будет практически полный контроль над кодом функции getenv. Тогда вы сможете проделывать всевозможные неприятные трюки. Ваш 'getenv' может обращаться к внешнему файлу конфигурации или сегменту SHM для получения альтернативных значений переменных env. Или вы можете выполнить поиск / замену регулярного выражения для запрошенных значений. Или же ...
Я не могу придумать простой способ сделать это для произвольных запущенных процессов (даже если вы - root), кроме как переписать динамический компоновщик (ld-linux.so).
Это должно быть выполнимо. У вас может быть небольшая база данных gdbm для пар var = value. У меня есть что-то подобное для malloc на stromberg.dnsalias.org/~strombrg/malloc-wrapper
Я думаю, что этот метод требует предусмотрительности. Вы также должны быть осторожны, чтобы случайно не применить его ко многим процессам.
По сути, нет. Если у вас были достаточные привилегии (root или около того) и вы пробовали / dev / kmem (память ядра), и вы внесли изменения в среду процесса, и если процесс действительно впоследствии повторно ссылался на переменную среды (то есть процесс еще не сделал копию env var и не использовал только эту копию), тогда, возможно, если вам повезло и умен, и ветер дул в правильном направлении, и фаза луны была правильной, возможно, вы можете чего-то добиться.
@kilaka: Ключевое слово - второе - Нет. Остальная часть ответа говорит о том, что если у вас есть привилегии root или вы используете отладчик, то, возможно, вы сможете это сделать, но для всех практических целей ответ - Нет.
У вас запущен сценарий оболочки; вы хотите изменить среду в родительском процессе вашего сценария оболочки ... поэтому сценарий оболочки запускает gdb
в родительском процессе и запускает сценарий для внесения изменений, и он работает без сбоя родительского процесса. Хорошо - вы, вероятно, сможете это сделать, но это не то, что вы собираетесь делать на регулярной основе. Поэтому для практических целей ответ остается Нет. Остальная часть ответа охватывает теоретически возможные и несколько непрактично выполнимые альтернативы.
Через GDB:
(gdb) attach process_id
(gdb) call putenv ("env_var_name=env_var_value")
(gdb) detach
Это довольно неприятный прием, и его, конечно же, следует делать только в контексте сценария отладки.
Таким образом, это, кажется, подразумевает, что вы действительно можете изменить среду процесса, если вы присоединитесь к процессу, как это делает GDB, а затем отсоединитесь. Кажется, можно было бы написать программу, которая делает только это.
"Кажется, можно было бы написать программу, которая только это делает". Действительно ... это так.
Он работает даже в Windows с использованием cygwin для процессов, которые не скомпилированы с использованием cygwin!
Обратите внимание, что это работает только в том случае, если процесс не кэшировал значение на постоянной основе после предыдущего getenv.
Удивительно, но это действительно работает. Я смог добавить переменную окружения к запущенному сеансу X / MATE, используя эту технику для mate-session и mate-panel. Недавно запущенные терминалы унаследовали переменную, как и обычно.
ptrace: Operation not permitted
Кстати. этот сценарий оболочки позволяетsudo export_pid FOO=bar 11234
с использованием метода GDB. Пс. gdb требует, чтобы вы запускались как root.
Я применил этот ответ, чтобы изменить часовой пояс в работающем экземпляре IRSSI, вызвав putenv («TZ = / path / to / timezone»).
Я получаю эту ошибку: No symbol "setenv" in current context.
Обновление: sourceware.org/gdb/onlinedocs/gdb.html#Environment это помогло.
В некоторых системах gdb может выдать следующую ошибку: 'putenv' has unknown return type; cast the call to its declared return type
; в этих случаях вы должны изменить вызов putenv
на этот: call (int) putenv ("env_var_name=env_var_value")
Что делать, если в процессе вы увеличиваете пространство, выделенное для env vars? Это перезаписывает что-то еще? То есть, если изначально VAR = valuex и вы используете gdbm для setenv / putenv VAR = valuexy, вы переполняете буфер?
Вы, вероятно, можете сделать это технически (см. Другие ответы), но это может вам не помочь.
Большинство программ ожидают, что переменные окружения не могут быть изменены извне после запуска, поэтому большинство, вероятно, просто прочитают переменные, которые им интересны, при запуске и инициализируются на основе этого. Так что изменение их впоследствии не имеет значения, поскольку программа никогда их не перечитает.
Если вы разместили это как конкретную проблему, вам, вероятно, следует использовать другой подход. Если бы это было просто из любопытства: Хороший вопрос :-).
Наиболее распространенный вариант использования, в котором было бы полезно, - это заставить дочерние процессы наследовать новые переменные среды, например, в среде рабочего стола, где вы хотите, чтобы новые терминалы использовали новые переменные.
Не прямой ответ, но ... Только на днях у Раймонда Чена было объяснение этому [на основе Windows].: -
... Although there are certainly unsupported ways of doing it or ways that work with the assistance of a debugger, there’s nothing that is supported for programmatic access to another process’s command line, at least nothing provided by the kernel. ...
That there isn’t is a consequence of the principle of not keeping track of information which you don’t need. The kernel has no need to obtain the command line of another process. It takes the command line passed to the
CreateProcess
function and copies it into the address space of the process being launched, in a location where theGetCommandLine
function can retrieve it. Once the process can access its own command line, the kernel’s responsibilities are done.Since the command line is copied into the process’s address space, the process might even write to the memory that holds the command line and modify it. If that happens, then the original command line is lost forever; the only known copy got overwritten.
Другими словами, любые такие средства ядра будут
Однако наиболее вероятная причина просто в том, что существует ограниченное количество вариантов использования такого средства.
UNIX полон межпроцессного взаимодействия. Проверьте, есть ли у вашего целевого экземпляра. Dbus становится стандартом в «настольных» IPC.
Я меняю переменные окружения внутри оконного менеджера Awesome, используя потрясающий клиент с Dbus «отправителем» кода lua.
Кажется, что путенв сейчас не работает, а 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
Мне это кажется более чем уродливым. Какую проблему вы хотите решить?