如何更改环境变量并应用于 tmux 会话中的所有窗口

6

我想知道是否有一种简单的方法可以更改bash环境变量并在tmux会话中应用到Windows?

我已经搜索过并没有找到解决方案,所以我在这里发布这个问题。

谢谢!


3
让我猜猜:您正在寻找一种方法,在重新连接会话后为所有窗口设置$DISPLAY - kynan
4个回答

5

您无法直接更改环境变量。

但是,您可以使位于tmux实例内的shell终端获取新变量。这需要几个步骤。

首先,tmux可以在自身中更新环境变量。配置指令update-environment可以实现此功能。列在此处的任何变量都将自动更新-连接到tmux会话会使用刚刚连接的客户端的值更新会话的环境变量。因此,如果您运行tmux attach并设置了SSH_AUTH_SOCK,那么tmux会话将获取SSH_AUTH_SOCK的新值。

然而,这仅更新会话的变量,因此只有新的窗格/窗口才能获取值。现有窗口仍将具有旧值。正如@IgnacioVazquez-Abrams所说,没有直接修复此问题的方法。

但是,在许多程序中可以解决它。足够新的tmux版本具有show-environment命令,该命令查询环境变量的当前值。这允许您在update-environment逻辑后从程序中获取环境变量。

例如,您可以使某些shell获取新值。在ZSH中,我使用~/.zshrc中的precmd钩子来实现这一点:

_update_ssh_agent() {
    local var
    var=$(tmux show-environment |grep '^SSH_AUTH_SOCK=')
    if [ "$?" -eq 0 ]; then
        eval "$var"
    fi
}
if [[ -n "$TMUX" ]]; then
    add-zsh-hook precmd _update_ssh_agent
fi

这使得在tmux会话中的shell每次显示新提示符时都会更新SSH代理。重新连接后,我只需在提示符下按Enter键,它就会抓取新的SSH代理连接。
Bash也有一个预命令机制,但我不知道如何即时配置它。您还可以配置更多程序使用show-environment来更新自己,例如vim或emacs。但是,您需要单独为每个想要执行此操作的程序进行配置。

3

不行。

即使使用一些不可移植的方法来修改其他进程的环境变量,也没有简便的方法。


3

这是一个旧问题,但当我在寻找我想要做的事情时它又出现了,所以这里有另一个解决方案。

当启动tmux时,它将环境复制到全局环境中。当创建新窗口时,它会将全局环境与会话环境合并,以设置该窗口的环境。我们可以使用以下命令查看这些环境:

tmux show-environment [-g] [-t target-session]

更好的是,我们还可以更新环境,甚至可以在Windows自己的tmux会话中进行更新:
tmux set-environment [-gru] [-t target-session] name [value]

有关标记的完整说明,请参见tmux手册

这个功能正是我想要的。不幸的是,它不会更新现有shell的环境变量,但我们可以轻松地循环使用tmux showenv -g来重新导出可能由其他进程设置的tmux环境。


这是我的用例:

按照我的shell配置方式,我在登录shell中导出我的环境变量,然后执行tmux会话。我想,既然环境变量不经常更改,我不需要在每次新的非登录shell中源它们。然而,当它们发生变化时,我不想重新启动整个tmux会话以使新的tmux窗口了解更改。虽然使用update-environment选项和重新连接可以解决会话重启问题,但在我的tmux配置中维护一个潜在可塑性环境变量的显式列表是很麻烦的。

通过以下函数,我们可以在像~/.shenv这样的文件中更新我们的环境变量,而不是源文件(. ~/.shenv),我们可以将文件提升promote ~/.shenv)以便新的tmux窗口从此更新的环境中继承。

promote() {
    sourced="$1"; shift
    . "$sourced"
    env - \
        "HOME=$HOME" \
        sh -c ". $sourced; env" | cut -d= -f1 | while read -r var; do
            val="$(eval "echo \"\$$var\"")"
            tmux set-environment -gt local "$var" "$val"
        done
}

这里发生的事情是我们在一个空环境下(除了我们添加的HOME)从shell中获取文件,并打印出我们的新环境变量。我们将它们管道传输到cut中,以提取每行的变量,并将其存储在名为var的变量中。通过使用eval进行一些元操作来获取当前shell中该变量的间接值,我们更新了tmux目标会话。在本例中,local是我们的tmux会话名称。

1
在尝试了不同的解决方案后,我编写了以下bash函数并将其添加到我的.bashrc文件中:
if [[ -n $TMUX ]]; then
  _fix_ssh_agent_in_tmux () { if [[ ! -S $SSH_AUTH_SOCK ]]; then eval export $(tmux show-env | grep SSH_AUTH_SOCK); fi }
  ssh ()   { _fix_ssh_agent_in_tmux; command ssh $@; }
  scp ()   { _fix_ssh_agent_in_tmux; command scp $@; }
  rsync () { _fix_ssh_agent_in_tmux; command rsync $@; }
fi

如果shell在tmux中运行,它会重新定义“ssh”为一个bash函数,该函数会在实际运行真正的ssh命令之前测试和修复SSH_AUTH_SOCK。
请注意,tmux show-env -g还返回SSH_AUTH_SOCK的值,但那个值已经过时了,我认为它是从tmux服务器启动时开始的。上面的命令查询当前tmux会话的环境,这似乎是正确的。
我正在使用tmux 2.6(随Ubuntu 18.04一起提供)它似乎工作得很好。

我发现另一个有用的命令可以添加到列表中,那就是 gitif [[ -n $TMUX ]]; then ... git () { _fix_ssh_agent_in_tmux; command git "$@"; } fi - forty_two

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接