如何在.tmux.conf中编写if语句为不同的tmux版本设置不同的选项?

时间:2016-01-26 14:39:46

标签: bash shell if-statement scripting tmux

我有一个.tmux.conf,我在安装了不同tmux版本的不同机器上使用。

我想设置不同的鼠标选项,具体取决于tmux版本。 在一台计算机上,我在另一台2.0上有2.1版本。

我说不出正确的意思

if "[[(( $(tmux -V | cut -c 6-) < 2.1 ))]]" \
  "set -g mode-mouse on;" \
  "set -g mouse-resize-pane on;" \
  "set -g select-pane on;" \
  "set -g select-window on" "set -g mouse on"

当我找到文件时

$ tmux source-file .tmux.conf

我收到此消息

.tmux.conf:12: unknown command: set -g mouse-resize-pane on

我运行它的机器有版本2.1所以它不应该设置四个选项。

我想在运行tmux 2.0或更少时设置四个选项,或者在运行tmux 2.1时设置一个选项。

此bash语句有效

$ tmux -V
tmux 2.1
$ if [[(( $(tmux -V | cut -c 6-) < 2.1 ))]];then echo $?;else echo $?;fi
1

11 个答案:

答案 0 :(得分:34)

基于@ericx's answer@thiagowfx's answer我将以下内容放在一起,涵盖版本2.0以后的listed incompatibilties

# Version-specific commands [grumble, grumble]
# See: https://github.com/tmux/tmux/blob/master/CHANGES
run-shell "tmux setenv -g TMUX_VERSION $(tmux -V | cut -c 6-)"

if-shell -b '[ "$(echo "$TMUX_VERSION < 2.1" | bc)" = 1 ]' " \
    set -g mouse-select-pane on; set -g mode-mouse on; \
    set -g mouse-resize-pane on; set -g mouse-select-window on; \
    set -g message-fg red; \
    set -g message-bg black; \
    set -g message-attr bright; \
    set -g window-status-bg default; \
    set -g window-status-fg default; \
    set -g window-status-current-attr bold; \
    set -g window-status-current-bg cyan; \
    set -g window-status-current-fg default; \
    set -g window-status-bell-fg red; \
    set -g window-status-bell-bg black; \
    set -g window-status-activity-fg white; \
    set -g window-status-activity-bg black"

# In version 2.1 "mouse" replaced the previous 4 mouse options
if-shell -b '[ "$(echo "$TMUX_VERSION >= 2.1" | bc)" = 1 ]' \
  "set -g mouse on"

# UTF8 is autodetected in 2.2 onwards, but errors if explicitly set
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.2" | bc)" = 1 ]' \
  "set -g utf8 on; set -g status-utf8 on; set -g mouse-utf8 on"

# bind-key syntax changed in 2.4 -- selection / copy / paste
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.4" | bc)" = 1 ]' " \
   bind-key -t vi-copy v   begin-selection; \
   bind-key -t vi-copy V   send -X select-line; \
   bind-key -t vi-copy C-v rectangle-toggle; \
   bind-key -t vi-copy y   copy-pipe 'xclip -selection clipboard -in'"

# Newer versions
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.9" | bc)" = 1 ]' " \
   bind-key -T copy-mode-vi v   send -X begin-selection; \
   bind-key -T copy-mode-vi V   send -X select-line; \
   bind-key -T copy-mode-vi C-v send -X rectangle-toggle; \
   bind-key -T copy-mode-vi y   send -X copy-pipe-and-cancel 'xclip -selection clipboard -in'"

if-shell -b '[ "$(echo "$TMUX_VERSION >= 2.9" | bc)" = 1 ]' \
   "set -g message-style fg=red,bg=black; \
    set -g message-style bright; \
    set -g window-status-style          fg=default,bg=default; \
    set -g window-status-current-style  fg=default,bg=cyan,bold; \
    set -g window-status-bell-style     fg=red,bg=black; \
    set -g window-status-activity-style fg=white,bg=black"

我提出了tmux的非向后兼容here问题。摘要是tmux开发人员不支持向后兼容性,他们也不会采用版本编号方案,突出显示哪些版本包含重大更改。

我还向support numeric comparators for %if提出了一个问题。

答案 1 :(得分:17)

if-shell并不总是有效。相反,我使用shell脚本来加载正确版本的tmux.conf:

在.tmux.conf中:

run-shell "bash ~/.tmux/verify_tmux_version.sh"

在verify_tmux_version.sh中:

#!/bin/bash

verify_tmux_version () {
    tmux_home=~/.tmux
    tmux_version="$(tmux -V | cut -c 6-)"

    if [[ $(echo "$tmux_version >= 2.1" | bc) -eq 1 ]] ; then
        tmux source-file "$tmux_home/tmux_2.1_up.conf"
        exit
    elif [[ $(echo "$tmux_version >= 1.9" | bc) -eq 1 ]] ; then
        tmux source-file "$tmux_home/tmux_1.9_to_2.1.conf"
        exit
    else
        tmux source-file "$tmux_home/tmux_1.9_down.conf"
        exit
    fi
}

verify_tmux_version

了解更多详情: https://gist.github.com/vincenthsu/6847a8f2a94e61735034e65d17ca0d66

答案 2 :(得分:15)

这是一种麻烦。在tmux 中执行此操作的正确方法(不依赖于外部shell脚本)结合了Vincent和jdloft的响应功能。

tmux中的if-shell命令用作

if-shell [-bF] [-t target-pane] shell-command command [command]
               (alias: if)
    Execute the first command if shell-command returns success or the second command otherwise.  Before
    being executed, shell-command is expanded using the rules specified in the FORMATS section, including
    those relevant to target-pane.  With -b, shell-command is run in the background.

    If -F is given, shell-command is not executed but considered success if neither empty nor zero (after
         formats are expanded).

请注意,tmux shell-command扩展将扩展#{pane_current_path}形式的变量,否则将保留命令。

更重要的是,请注意tmux uses /bin/sh -c来执行我们指定的shell命令。因此,命令must be POSIX compliant,因此不能保证形式[[的测试是可移植的。现代的Ubuntu和Debian系统,例如,符号链接/bin/shdash

我们希望运行一个POSIX兼容的shell命令来测试tmux版本,如果找到了所需的版本,则返回0(true)。

if-shell '[ $(echo "$(tmux -V | cut -d" " -f2) >= 2.1" | bc) -eq 1 ]' \
    'command if true' \
    'command if false'

示例:

if-shell '[ $(echo "$(tmux -V | cut -d" " -f2) >= 2.1" | bc) -eq 1 ]' \
    'set -g mouse on; set -g mouse-utf8 on' \
    'set -g mode-mouse on; set -g mouse-resize-pane on; set -g mouse-select-pane on; set -g mouse-select-window on' 

这正确地处理了我们正在进行浮点运算的事实,因此bc is required。此外,不需要if / then / else / fi构造,因为[运算符本身会产生一个真值。

几个笔记

  • 继续到下一行的行不能有尾随注释,或者tmux会给出“未知命令”错误消息。
  • “if if false”可以省略。
  • 可以使用;
  • 组合用于true或false的多个命令
  • 使用/bin/sh -c在底层shell上运行该命令。使用[[或其他非POSIX语法的其他方法无法保证正常工作。

编辑:此答案的先前版本使用[[,但不适用于不使用bash的系统。用[替换解决了这个问题。

答案 3 :(得分:7)

Tmux的if-shell可用于检查ZSH版本。

[[ `tmux -V | cut -d' ' -f2` -lt 2.1 ]]

检查tmux版本是否大于或等于2.1。使用此功能,我们可以根据ZSH版本设置鼠标命令。

if-shell "[[ `tmux -V | cut -d' ' -f2` -lt 2.1 ]]" \
    'set -g mode-mouse on; set -g mouse-resize-pane on; set -g mouse-select-pane on; set -g mouse-select-window on'

并将其设置为更高版本的tmux:

if-shell "[[ `tmux -V | cut -d' ' -f2` -ge 2.1 ]]" \
    'set -g mouse on; set -g mouse-utf8 on'

答案 4 :(得分:6)

在某些机器上,我用双括号('[[')语法得到假阳性结果。所以我想出了一个使用awk的替代方案:

# Enable mouse for different versions of tmux
# (If 'awk' exits with status 0, 'if-shell' evaluates to true)
# tmux < v2.1:
if-shell "tmux -V | awk '{exit !($2 < \"2.1\")}'" \
    "setw -g mode-mouse on ; set -g mouse-select-pane on ; set -g mouse-resize-pane on ; set -g mouse-select-window on ;"
# tmux >= v2.1:
if-shell "tmux -V | awk '{exit !($2 >= \"2.1\")}'" \
    "set -g mouse on ;"

答案 5 :(得分:6)

我还发现了不同tmux版本中的配置不匹配问题。在此处和this related question on SuperUser中查看了所有解决方案之后,我实施了以下变体:

# Version-specific configuration can be placed in ~/.tmux/${TMUX_VERSION}/*.conf
run-shell "for conf in ~/.tmux/$(tmux -V | cut -d' ' -f2)/*.conf; do tmux source-file \"\$conf\"; done"

有了这个,特定于版本的配置可以放入特定版本的(多个)配置片段中。这类似于@VincentHsu的解决方案,但是:

  • 它不需要外部shell脚本。
  • 它不会分为固定版本范围(... / 1.9到2.0 / 2.1 ......)。相反,可以使用(sym)链接在多个tmux版本之间共享配置代码段。
  • 它不会对版本的单个文件名进行硬编码。通过为每个版本允许多个配置代码段,可以在版本之间共享部分,而其他部分则保持特定于版本。这应该提供最大的灵活性。
  • 原始~/.tmux.conf中只有一个配置元素。其他解决方案(如@TomHale中的解决方案)会复制每个配置元素的版本测试。

答案 6 :(得分:0)

我将建议的解决方案结合到了可行的解决方案中(在tmux 1.8和2.7上进行了测试):

run-shell "tmux setenv -g TMUX_VERSION $(tmux -V | cut -c 6-)"

if-shell -b '[[ "$TMUX_VERSION" < "2.6" ]]' \
  "bind w choose-tree -u"

if-shell -b '[[ "$TMUX_VERSION" < "2.2" ]]' \
  "set -g status-utf8 on"

答案 7 :(得分:0)

当前的最新版本是2.9a,它引发了此处使用的许多直接比较。

我的选择是使用sort -V,它在处理版本比较方面更加强大。

# ver >= 2.3
[ ! "$(printf "%s\n%s" "$TMUX_VERSION" "2.3" | sort -V | head -n1)" == "$TMUX_VERSION" ]' \
    "command"

# ver > 2.3
[ ! "$(printf "%s\n%s" "$TMUX_VERSION" "2.4" | sort -V | head -n1)" == "$TMUX_VERSION" ]' \
    "command"

# ver < 2.3
[ "$(printf "%s\n%s" "$TMUX_VERSION" "2.3" | sort -V | head -n1)" == "$TMUX_VERSION" ]' \
    "command"

答案 8 :(得分:0)

这不是替代方案,而是对已接受答案的扩展-(汤姆·黑尔的答案是最可靠,最完整的)。

要在.tmux.conf中减少重复,可以将shell测试字符串存储在tmux env vars (available since 0.8 in 2008)中,并在运行时为if-shell内插它们:

# Use which sed pattern actually works in the accepted answers
run-shell 'tmux setenv -g TMUX_VERSION $(tmux -V | sed -En "...")'

# Setup condition checks
V33_GTE='[ "$(echo "$TMUX_VERSION >= 3.3" | bc)" = 1 ]' 
V33_LT='[ "$(echo "$TMUX_VERSION < 3.3" | bc)" = 1 ]'

# So on for other versions
# ...

### Example binding
# Toggle mouse
bind m set -g mouse on  \; display 'Mouse: ON'
bind M set -g mouse off \; display 'Mouse: OFF' 

# As of 3.1 you can annotate your keybindings
# As of 3.3 you can attach a note to existing bindings without setting the binding
# If running >= 3.3 , attach a note to the binding for `list-keys -N`

if "$V33_GTE" bind -N "Enable mouse mode" m
if "$V33_GTE" bind -N "Disable mouse mode" M

答案 9 :(得分:0)

我最近遇到了这个问题,我的解决方案是编写一个“ tmux-older-than”脚本:

from data-lake.libs.utils.operators import airflow_utils

这使tmux.conf更具可读性:

#! /bin/bash

TMUX_VERSION="$(tmux -V | cut -d" " -f2)"
test 1 -eq "$( echo "$TMUX_VERSION < $1" | bc)"

答案 10 :(得分:0)

我有这个配置很多年了。

  • 支持 tmux 2.4 tmux 2.4a tmux next-3.3 等版本
  • bc 命令
  • 支持 Cygwin、macOS 和 Linux
# Tmux version before 2.4
if-shell -b '[ `tmux -V | cut -d" " -f2 | tr -d " |\-|.|[:alpha:]"` -lt 24 ]' \
  'bind-key -t vi-copy v begin-selection; \
    bind-key -t vi-copy Q cancel; \
    bind-key -t vi-copy Enter cancel'

# Tmux version 2.4 onwards
if-shell -b '[ `tmux -V | cut -d" " -f2 | tr -d " |\-|.|[:alpha:]"` -ge 24 ]' \
  'bind-key -T copy-mode-vi C-w   send-keys -X cancel; \
bind-key -T copy-mode-vi C-u   send-keys -X halfpage-up; \
bind-key -T copy-mode-vi C-j   send-keys -X halfpage-down; \
bind-key -T copy-mode-vi C-l   send-keys -X select-line'