this doesn't modify anything outside the environment block of the python process
It doesn't even do that. It modifies the environment block of the child /bin/sh -c "export..."
process that system() invokes, and the modifications are immediately lost – they do not propagate 'upwards' to the Python process either. (Check os.environ["PS1"]
if in doubt. In fact, why aren't you setting os.environ directly?)
(Besides that, Bash has a separate set of "shell variables". There's significant overlap between the two – environment variables are imported during shell startup, and shell variables can be marked for export to child environments – but the key point is that even if you update Bash's environment block "from the outside", it won't actually update the shell variable $PS1 that Bash really uses.)
That said, a common trick to update a process' environment "from the outside" (and practically the only way) is to attach a debugger to the process and call the corresponding function that modifies the environment as seen by the program itself:
$ gdb -p <pid>
(gdb) p (int) putenv("FOO=bar")
$0 = 0
(gdb) p (char*) getenv("FOO")
$1 = 0x55bb09f61404 "bar"
This will actually work with PS1 because Bash carries its own implementation of getenv() and putenv(), overriding the usual libc version. That custom implementation doesn't actually update environ
, instead it updates the corresponding shell variable. Calling putenv("PS1=foo")
through a debugger will therefore update the shell prompt.
But it's quite frankly a horrible solution to the real problem. If you want the shell prompt to always show the current IP address, just make the prompt itself check what the correct value is.
Bash allows you to include literal expansions such as $var
or even $(cmd)
within $PS1, and they will be expanded every time the prompt is shown. For example (note the \$
being escaped):
$ PS1="<now=\$(date +%X)> " ↵
<now=03:27:02 PM> ↵
<now=03:27:04 PM> ↵
<now=03:27:07 PM> ↵
<now=03:27:08 PM> ↵
So in order to apply this to your "IP updater" script,
Instead of trying to change all environments, simply make the script write out the IP address to a file (say, /tmp/current-ip
).
Make your shell prompt read from that file, using the $(< filename)
expansion:
PS1="@\$(</tmp/current-ip)>"
That's it. You don't need to go through all environment blocks to do this – each shell will automatically re-read the file the next time the prompt has to be displayed. For example:
$ echo 1.1.1.1 > /tmp/current-ip ↵
$ PS1="@\$(< /tmp/current-ip)> " ↵
@1.1.1.1> ↵
@1.1.1.1> echo 22.22.22.22 > /tmp/current-ip ↵
@22.22.22.22>
1Does this script run periodically? Does it report the system's own address straight from ifconfig, or does it report the results from querying a remote "whatismyip" service? – user1686 – 2019-07-03T12:24:49.853
it's more complicated than that. I want to add other python variables. I tried to simply a little bit ;) – hotips – 2019-07-03T15:05:59.467
The same story applies to all of them. There is no good way to "push" any variables to other processes -- they must themselves "pull" the data. – user1686 – 2019-07-03T16:54:44.747