自定义 Bash Prompt 并将修改应用于所有登录用户

自定义 Bash Prompt 并将修改应用于所有登录用户

我有一个具有动态 IP 地址的 Linux。我想根据当前 IP 更改 bash 提示符。python 脚本负责此连接并在启动时启动。

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

命令已执行,但这不会修改 python 进程环境块之外的任何内容:并非所有已登录的用户或将来会登录的用户。

然后我的想法是为每个用户更改 .bashrc 或 /etc/bashrc。这将解决新连接的问题,但不能解决已打开的连接的问题。

答案1

这不会修改 Python 进程环境块之外的任何内容

它甚至没有这样做。它修改了/bin/sh -c "export..."system() 调用的子进程的环境块,并且修改立即丢失 - 它们也不会“向上”传播到 Python 进程。(os.environ["PS1"]如果有疑问,请检查。事实上,你为什么不直接设置 os.environ?)

(除此之外,Bash 还有一组单独的“shell 变量”。两者之间有很大的重叠——环境变量在 shell 启动时导入,shell 变量可以标记为导出到子环境——但关键点在于即使如果你“从外部”更新 Bash 的环境块,它实际上不会更新shell 变量Bash 真正使用的 $PS1。)

也就是说,从“外部”更新进程环境的一个常见技巧(实际上也是唯一的方法)是将调试器附加到进程并调用相应的函数来修改程序本身所见的环境:

$启动gdb<进程ID>
(GDB)p (int)putenv(“FOO = bar”)
$0 = 0
(GDB)p (char*) getenv(“FOO”)
$1 = 0x55bb09f61404 “酒吧”

这实际上可以与 PS1 一起使用,因为 Bash 带有自己的 getenv() 和 putenv() 实现,覆盖了通常的 libc 版本。该自定义实现实际上不会更新environ,而是更新相应的 shell 变量。putenv("PS1=foo")因此,通过调试器调用将更新 shell 提示符。

但坦率地说,对于真正的问题来说,这是一个糟糕的解决方案。如果你想让 shell 提示始终显示当前 IP 地址,只需提示本身检查正确的值是多少。

Bash 允许您在 $PS1 内包含文字扩展,例如$var$(cmd),并且每次显示提示时它们都会被扩展。例如(注意被\$转义):

$ PS1="<now=\$(date +%X)> " ↵
<now=03:27:02 PM> ↵
<now=03:27:04 PM> ↵
<now=03:27:07 PM> ↵
<now=03:27:08 PM> ↵

因此,为了将其应用到你的“IP 更新程序”脚本,

  1. 无需尝试更改所有环境,只需让脚本将 IP 地址写入文件(例如/tmp/current-ip)。

  2. 使用扩展名让你的 shell 提示符从该文件读取$(< filename)

    PS1="@\$(</tmp/current-ip)>"
    

就是这样。您不需要遍历所有环境块来执行此操作 - 每个 shell 将在下次显示提示时自动重新读取该文件。例如:

$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>

相关内容