Customize Bash Prompt and apply the modification for all logged users

0

I have a linux with dynamic IP address. I would like to change the bash prompt according to the current IP. A python script is responsible for this connection and his launched at boot.

os.system('export PS1="\u@'+str(self.ip)+'>"')

The command is executed but this doesn't modify anything outside the environment block of the python process : not all the users logged or those who will log in the future.

The idea was then to change .bashrc for each user or /etc/bashrc. It will solve the problem for new connections but not for the opened.

hotips

Posted 2019-07-03T11:48:52.690

Reputation: 145

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

Answers

2

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,

  1. Instead of trying to change all environments, simply make the script write out the IP address to a file (say, /tmp/current-ip).

  2. 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>

user1686

Posted 2019-07-03T11:48:52.690

Reputation: 283 655

1How am I ever going to catch you up if you keep writing such excellent answers? ;) – DavidPostill – 2019-07-03T12:45:15.413