在 tmux 中拆分窗格时保持旧的 conda env 处于激活状态
Keeping the old conda env activated upon splitting panes in tmux
我使用的是 tmux 2.6 并且正在使用几个不同的 conda 环境。拆分后 panes/windows 我希望 tmux 也能在子窗格中激活父窗格的环境。
我知道我可以在 split-window 命令的键绑定中添加要执行的代码,并且当前活动的 conda env 的名称存储在 $CONDA_DEFAULT_ENV
中。但是,我尝试的任何命令都失败了。
为了我的尝试,我在 /some_path/bla.sh
中设置了 conda activate $CONDA_DEFAULT_ENV
并使用
设置了窗格拆分命令
bind \ split-window -h -c "#{pane_current_path}" '/some_path/bla.sh'
在我的 tmux 配置文件中,但新创建的窗格在拆分后立即消失。
然而,即使它没有,我猜它也会重新激活基本环境,因为 $CONDA_DEFAULT_ENV
环境变量随着新 shell 的启动而改变。
我想一个可行的解决方案必须首先存储旧的 $CONDA_DEFAULT_ENV 环境变量,将其转移到新的 tmux 面板,然后使用它来设置 conda 环境,但我不知道如何实现这一目标。
我已经使用 tmux 3.1b 完成了这项工作。我看到你在发布问题时是 运行 tmux 2.6,但是如果可以的话,请尝试至少更新到 v3.0,因为我的回答依赖于使用 -e
标志来new-window
和 split-window
并且该标志仅根据 their changelog 从 v3.0 引入。假设你可以使用前面提到的-e
标志,步骤如下:
步骤 1(使用 tmux/tmux.conf):
在 运行 tmux new-window
或 tmux split-window
时传递 -e "TMUX_PARENT_PANE_ID=#{pane_id}"
,以及您可能已经使用的任何其他标志。这会在新(子)pane/window 的环境中创建一个变量 TMUX_PARENT_PANE_ID
,其中包含由 tmux 分配给初始(父)窗格的唯一 ID。
如果您使用键绑定,那么您需要使用 tmux 的 run
以一种不太直观的方式(重新)编写它们。例如,为了将字母 "c" 绑定到 tmux new-window
,tmux.conf 文件中的相应行必须如下所示:
bind c run 'tmux new-window YOUR_CURRENT_OPTIONS -e "TMUX_PARENT_PANE_ID=#{pane_id}"'
其中 YOUR_CURRENT_OPTIONS
代表您在添加 -e
选项之前可能已经存在的任何选项。如果您只使用 bind c new-window YOUR_CURRENT_OPTIONS -e "TMUX_PARENT_PANE_ID=#{pane_id}"
,那么 #{pane_id}
将作为文字 "#{pane_id}"
传递,接下来的步骤将不起作用。
设置 2 [在您的 bashrc(或等效文件)文件中]:
重新定义 conda
命令以便:
- 在每个窗格的本地环境中复制 anaconda 的
CONDA_DEFAULT_ENV
环境变量。在接下来的代码中,这个副本将被命名为 CONDA_DEFAULT_ENV_COPY
。如果再次获取 bashrc(或相应的等效文件),这将有助于在窗格中调用 conda 环境。
- 跟踪 tmux 会话所有面板的 conda 环境变化。我们通过 defining/updating a
TMUX_SESSION_CONDA_ENVS
tmux session 环境变量来做到这一点。与每个窗格的本地环境中定义的变量相反,会话中的所有窗格都可以访问 tmux 会话变量。
完成上述内容的代码是:
# Redefine conda command, part a: Keep copy of original conda command/function
eval "original_$(declare -f conda)" 2> /dev/null
if [ $? -ne 0 ]; then
original_conda () {
command conda "$@"
}
fi
# Redefine conda command, part b: Add new functionality related to items (i) and (ii).
conda () {
# Run the regular conda
original_conda "$@"
local CONDA_RTN_CODE=$?
# Keep a copy of CONDA_DEFAULT_ENV to restore the environment if, e.g.,
# 'source ~/.bashrc' is run
CONDA_DEFAULT_ENV_COPY=$CONDA_DEFAULT_ENV
# Stop and return original_conda's return code if it fails
[ $CONDA_RTN_CODE -ne 0 ] && return $CONDA_RTN_CODE
# Do tmux-related stuff, but only if tmux is running and "$@" contains substring "activate"
if [[ -n "$TMUX" ]] && [[ "$@" =~ .*"activate".* ]]; then
# Create/update the *tmux* session env var "TMUX_SESSION_CONDA_ENVS"
local TMUX_SESSION_CONDA_ENVS=$(tmux showenv TMUX_SESSION_CONDA_ENVS 2>/dev/null)
if [[ $? -eq 0 ]]; then
# Get list of conda envs for all panes except the current one
local OLD_VALUES=$(echo $TMUX_SESSION_CONDA_ENVS | sed "s/TMUX_SESSION_CONDA_ENVS=//")
local CONDA_ENV_OTHER_PANES=$(echo $OLD_VALUES | sed "s/$TMUX_PANE:\w*[[:space:]]*//g")
fi
# Include current pane's conda env info
tmux setenv TMUX_SESSION_CONDA_ENVS "$TMUX_PANE:$CONDA_DEFAULT_ENV $CONDA_ENV_OTHER_PANES"
fi
}
步骤 3 [也在您的 bashrc(或等效文件)文件中]:
查询创建child时父pane的conda环境,最后激活child中的conda环境。我目前使用的代码如下:
if [[ -n "$TMUX_PARENT_PANE_ID" ]]; then
# Remember: "TMUX_SESSION_CONDA_ENVS", as per our redefined "conda" command, carries
# info about changes in the the conda environments in all the session's panes.
# TMUX_PARENT_PANE_ID makes it thus possible to query, from any child
# pane, its parent's conda environment at the time the child was created.
# This is exactly what will be done now.
TMUX_SESSION_CONDA_ENVS=$(tmux showenv TMUX_SESSION_CONDA_ENVS 2>/dev/null)
if [ $? -eq 0 ]; then
PATT="(?<=${TMUX_PARENT_PANE_ID}:).*?(?=([[:space:]]|$))"
PARENT_CONDA_ENV=$(echo $TMUX_SESSION_CONDA_ENVS | grep -oP "$PATT" | head -1)
echo "Activate conda env '$PARENT_CONDA_ENV' of parent tmux pane '$TMUX_PARENT_PANE_ID'"
conda activate $PARENT_CONDA_ENV
fi
# Clean up the pane's env (TMUX_SESSION_CONDA_ENVS remains in the tmux session env)
unset TMUX_SESSION_CONDA_ENVS PATT PARENT_CONDA_ENV
# Erase memory of parent tmux pane's ID so that the 'else' block below
# is run if we re-source bashrc
unset TMUX_PARENT_PANE_ID
else
# Triger update of TMUX_SESSION_CONDA_ENVS and CONDA_DEFAULT_ENV_COPY
# when the pane has no parent (very first pane or a pane where bashrc was
# re-sourced after creation).
[[ -n "$CONDA_DEFAULT_ENV_COPY" ]] && echo "Activate previous conda env '$CONDA_DEFAULT_ENV_COPY'"
conda activate $CONDA_DEFAULT_ENV_COPY
fi
完成这些步骤后,只需关闭您的终端,再次打开它们并重新启动 tmux。希望对您有所帮助。
我使用的是 tmux 2.6 并且正在使用几个不同的 conda 环境。拆分后 panes/windows 我希望 tmux 也能在子窗格中激活父窗格的环境。
我知道我可以在 split-window 命令的键绑定中添加要执行的代码,并且当前活动的 conda env 的名称存储在 $CONDA_DEFAULT_ENV
中。但是,我尝试的任何命令都失败了。
为了我的尝试,我在 /some_path/bla.sh
中设置了 conda activate $CONDA_DEFAULT_ENV
并使用
bind \ split-window -h -c "#{pane_current_path}" '/some_path/bla.sh'
在我的 tmux 配置文件中,但新创建的窗格在拆分后立即消失。
然而,即使它没有,我猜它也会重新激活基本环境,因为 $CONDA_DEFAULT_ENV
环境变量随着新 shell 的启动而改变。
我想一个可行的解决方案必须首先存储旧的 $CONDA_DEFAULT_ENV 环境变量,将其转移到新的 tmux 面板,然后使用它来设置 conda 环境,但我不知道如何实现这一目标。
我已经使用 tmux 3.1b 完成了这项工作。我看到你在发布问题时是 运行 tmux 2.6,但是如果可以的话,请尝试至少更新到 v3.0,因为我的回答依赖于使用 -e
标志来new-window
和 split-window
并且该标志仅根据 their changelog 从 v3.0 引入。假设你可以使用前面提到的-e
标志,步骤如下:
步骤 1(使用 tmux/tmux.conf):
在 运行 tmux new-window
或 tmux split-window
时传递 -e "TMUX_PARENT_PANE_ID=#{pane_id}"
,以及您可能已经使用的任何其他标志。这会在新(子)pane/window 的环境中创建一个变量 TMUX_PARENT_PANE_ID
,其中包含由 tmux 分配给初始(父)窗格的唯一 ID。
如果您使用键绑定,那么您需要使用 tmux 的 run
以一种不太直观的方式(重新)编写它们。例如,为了将字母 "c" 绑定到 tmux new-window
,tmux.conf 文件中的相应行必须如下所示:
bind c run 'tmux new-window YOUR_CURRENT_OPTIONS -e "TMUX_PARENT_PANE_ID=#{pane_id}"'
其中 YOUR_CURRENT_OPTIONS
代表您在添加 -e
选项之前可能已经存在的任何选项。如果您只使用 bind c new-window YOUR_CURRENT_OPTIONS -e "TMUX_PARENT_PANE_ID=#{pane_id}"
,那么 #{pane_id}
将作为文字 "#{pane_id}"
传递,接下来的步骤将不起作用。
设置 2 [在您的 bashrc(或等效文件)文件中]:
重新定义 conda
命令以便:
- 在每个窗格的本地环境中复制 anaconda 的
CONDA_DEFAULT_ENV
环境变量。在接下来的代码中,这个副本将被命名为CONDA_DEFAULT_ENV_COPY
。如果再次获取 bashrc(或相应的等效文件),这将有助于在窗格中调用 conda 环境。 - 跟踪 tmux 会话所有面板的 conda 环境变化。我们通过 defining/updating a
TMUX_SESSION_CONDA_ENVS
tmux session 环境变量来做到这一点。与每个窗格的本地环境中定义的变量相反,会话中的所有窗格都可以访问 tmux 会话变量。
完成上述内容的代码是:
# Redefine conda command, part a: Keep copy of original conda command/function
eval "original_$(declare -f conda)" 2> /dev/null
if [ $? -ne 0 ]; then
original_conda () {
command conda "$@"
}
fi
# Redefine conda command, part b: Add new functionality related to items (i) and (ii).
conda () {
# Run the regular conda
original_conda "$@"
local CONDA_RTN_CODE=$?
# Keep a copy of CONDA_DEFAULT_ENV to restore the environment if, e.g.,
# 'source ~/.bashrc' is run
CONDA_DEFAULT_ENV_COPY=$CONDA_DEFAULT_ENV
# Stop and return original_conda's return code if it fails
[ $CONDA_RTN_CODE -ne 0 ] && return $CONDA_RTN_CODE
# Do tmux-related stuff, but only if tmux is running and "$@" contains substring "activate"
if [[ -n "$TMUX" ]] && [[ "$@" =~ .*"activate".* ]]; then
# Create/update the *tmux* session env var "TMUX_SESSION_CONDA_ENVS"
local TMUX_SESSION_CONDA_ENVS=$(tmux showenv TMUX_SESSION_CONDA_ENVS 2>/dev/null)
if [[ $? -eq 0 ]]; then
# Get list of conda envs for all panes except the current one
local OLD_VALUES=$(echo $TMUX_SESSION_CONDA_ENVS | sed "s/TMUX_SESSION_CONDA_ENVS=//")
local CONDA_ENV_OTHER_PANES=$(echo $OLD_VALUES | sed "s/$TMUX_PANE:\w*[[:space:]]*//g")
fi
# Include current pane's conda env info
tmux setenv TMUX_SESSION_CONDA_ENVS "$TMUX_PANE:$CONDA_DEFAULT_ENV $CONDA_ENV_OTHER_PANES"
fi
}
步骤 3 [也在您的 bashrc(或等效文件)文件中]:
查询创建child时父pane的conda环境,最后激活child中的conda环境。我目前使用的代码如下:
if [[ -n "$TMUX_PARENT_PANE_ID" ]]; then
# Remember: "TMUX_SESSION_CONDA_ENVS", as per our redefined "conda" command, carries
# info about changes in the the conda environments in all the session's panes.
# TMUX_PARENT_PANE_ID makes it thus possible to query, from any child
# pane, its parent's conda environment at the time the child was created.
# This is exactly what will be done now.
TMUX_SESSION_CONDA_ENVS=$(tmux showenv TMUX_SESSION_CONDA_ENVS 2>/dev/null)
if [ $? -eq 0 ]; then
PATT="(?<=${TMUX_PARENT_PANE_ID}:).*?(?=([[:space:]]|$))"
PARENT_CONDA_ENV=$(echo $TMUX_SESSION_CONDA_ENVS | grep -oP "$PATT" | head -1)
echo "Activate conda env '$PARENT_CONDA_ENV' of parent tmux pane '$TMUX_PARENT_PANE_ID'"
conda activate $PARENT_CONDA_ENV
fi
# Clean up the pane's env (TMUX_SESSION_CONDA_ENVS remains in the tmux session env)
unset TMUX_SESSION_CONDA_ENVS PATT PARENT_CONDA_ENV
# Erase memory of parent tmux pane's ID so that the 'else' block below
# is run if we re-source bashrc
unset TMUX_PARENT_PANE_ID
else
# Triger update of TMUX_SESSION_CONDA_ENVS and CONDA_DEFAULT_ENV_COPY
# when the pane has no parent (very first pane or a pane where bashrc was
# re-sourced after creation).
[[ -n "$CONDA_DEFAULT_ENV_COPY" ]] && echo "Activate previous conda env '$CONDA_DEFAULT_ENV_COPY'"
conda activate $CONDA_DEFAULT_ENV_COPY
fi
完成这些步骤后,只需关闭您的终端,再次打开它们并重新启动 tmux。希望对您有所帮助。