【问题标题】:How to write if statement in .tmux.conf to set different options for different tmux versions?如何在 .tmux.conf 中编写 if 语句为不同的 tmux 版本设置不同的选项?
【发布时间】:2016-01-26 14:39:45
【问题描述】:

我有一个 .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

【问题讨论】:

  • 为什么你在那个测试中同时拥有[[ ]](( ))?我认为只要(( )) 就足够了,假设if(即if-shell?)测试返回码。
  • 将 if 语句修复为 if "(( $(tmux -V | cut -c 6-) &lt; 2.1 ))" "set -g mode-mouse on; set -g mouse-resize-pane on; set -g select-pane on; set -g select-window on" 解决了问题,您能否发表评论作为答案。
  • 实际上(( )) 无法处理十进制数字,因此如果可行,那是另一个原因(或意外)。 tmux 有办法测试功能吗? (我假设您只希望在支持它的版本中打开它。)
  • 我不知道tmux是否可以测试功能,我对tmux比较陌生。
  • 操作系统检测:superuser.com/questions/539595/…

标签: bash shell if-statement scripting tmux


【解决方案1】:

基于@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 | \
                           sed -En "s/^tmux[^0-9]*([.0-9]+).*/\1/p")'


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 提出了一个问题,即implemented in v3.0

【讨论】:

  • 谢谢汤姆,这太棒了。我已经在我的 repo github.com/sixarm/sixarm_tmux_dotfiles 中添加了感谢您
  • 作为在 OSX 和 2-3 个不同的 linux 机器上使用相同点文件的人,我感激不尽!这个答案似乎是所有答案中最通用的。
  • 这在 Micah 的回答中指出,但由于在反斜杠之前缺少分号(它都被解释为单个长命令),我遇到了问题。谢谢你的例子!
  • 需要注意的是,如果发布版本中有字母和其他字符,这些版本检查将不起作用。本着 tmux 的 FU SEMVER 的精神,我在 GitHub 上提供了无视这些版本检查的最后两个版本:2.9a3.0-rc3github.com/tmux/tmux/releases
  • 感谢@danemacmillan 的提醒。他们的发布管理是 FUBAR。我更新了一个sed -n
【解决方案2】:

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

【讨论】:

  • bc hack 是铁杆。
  • 配置管理已经不是简单的管理3个配置文件了。 tmux 开发人员 introduce incompatibilities quite a bit 并且可能会继续这样做。我更喜欢a solution using only .tmux.conf,我基于这个答案。
  • 我已经尝试了if-shell 解决方案,但是我找不到在我的 3 台机器(Ubuntu 14.04 (tmux 1.8)、Ubuntu 16.04 (tmux 2.1) 和macOS Sierra (tmux 2.3))。所以我选择直接调用bash。如果有人让“只有一个 .tmux.conf”工作,我会很高兴。
【解决方案3】:

这有点麻烦。 在 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} 形式的变量,否则将不理会命令。

更重要的是,注意tmuxuses/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' 

这正确地处理了我们正在做浮点运算的事实,所以bcis required。此外,不需要 if/then/else/fi 构造,因为 [ 运算符会自行生成真值。

一些笔记

  • 继续到下一行的行不能有尾随 cmets,否则 tmux 将给出“未知命令”错误消息。
  • “如果为 false 的命令”可以省略。
  • 可以使用; 组合多个判断为真或假的命令
  • 该命令使用/bin/sh -c 在底层shell 上运行。不保证使用 [[ 或其他非 POSIX 语法的其他方法有效。

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

【讨论】:

  • 我想知道是否有办法使用嵌套的 if 语句来完成这项工作。
  • 我相信你可以@Carl,但你对" 字符的引用会让人毛骨悚然。 @pana 在最后一个示例中,您需要在第 2 行和第 3 行之间添加一个 ;。此外,您有两次mouse。请参阅 my answer 以获取延续中的延续示例。
  • 次要:[ 不是操作符,而是命令。这只是一个重要的区别,因为许多人将[ 误认为是 shell 语法的一部分,而事实并非如此。
  • 这是一个很好的答案。我能够实现我所追求的目标,并且学到了一些关于 tmux 和 Bash 的东西。谢谢!
【解决方案4】:

我还偶然发现了不同 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"

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

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

【讨论】:

    【解决方案5】:

    在某些机器上,我使用双括号 ('[[') 语法得到了误报结果。所以我想出了一个使用 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 ;"
    

    【讨论】:

    • 绝妙的解决方案,这应该是公认的答案!谢谢(我会在tmux -V | 之后添加head -1 |,以防他们稍后在其描述中包含更多行。)
    • @Krisztian 应该没有必要,因为exit 已经导致awk 停止第一行的处理。
    • @raimue,谢谢,我不知道,它似乎确实有效:echo -e "tmux 2.0-master\ntmux 2.8" | awk '{exit !($2 &lt; "2.1")}' &amp;&amp; echo ok || echo no
    【解决方案6】:

    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'
    

    【讨论】:

    • tmux if-shell 配置似乎不起作用。即使使用 tmux 2.0,bash shell 对 if [[ $(tmux -V | cut -d' ' -f2) -lt 2.1 ]]; then echo 'true'; true; else echo 'false'; false; fi 表示正确,但对于 if-shell "if [[ $(tmux -V | cut -d' ' -f2) -lt 2.1 ]]; then true; else false; fi" "display true;" "display false;",tmux 表示 unknown command: display 2。这意味着shell 命令被评估为假。
    • 我遇到了同样的问题。 if-shell 总是得到错误的返回。有人可以请我吗?
    • 这根本行不通。只需尝试在 bash 中运行 [[ `tmux -V | cut -d' ' -f2` -lt 2.1 ]]。我得到-bash: [[: 2.2: syntax error: invalid arithmetic operator (error token is ".2")。原因是这些测试运算符不处理浮点数,您需要bc
    • 抱歉,我在 Z shell 中进行测试,它允许像这样使用“-lt”运算符。尝试用“”符号表示大于)替换它。
    • 只要有人做boolean ? true : false而不是boolean,猫就会死
    【解决方案7】:

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

    #! /bin/bash
    
    TMUX_VERSION="$(tmux -V | cut -d" " -f2)"
    test 1 -eq "$( echo "$TMUX_VERSION < $1" | bc)"
    

    这使得 tmux.conf 更具可读性:

    if-shell 'tmux-older-than 3.0' \
            'bind-key ^P swap-window -t -1' \
            'bind-key ^P swap-window -d -t -1'
    

    【讨论】:

      【解决方案8】:

      当前的最新版本是2.9a,它摒弃了这里使用的许多直接比较。

      我的替代方案使用sort -V,它在处理版本比较方面更加稳健。

      编辑:评论者指出 sort -V 在 BSD sort 中不可用,例如在本机 OSX 上。然而,这仍然是一个解释不是纯数字版本的答案。

      # 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"
      

      【讨论】:

      • 小心,sort -V 并不总是有效,例如它不适用于使用 BSD 的 macOS 10.11 sort
      • Drats,这是一个很好的警告。我通常将 gnu sort 放在我的 OSX 机器上,所以我错过了。我会在答案中添加警告。
      【解决方案9】:

      我有这个配置很多年了。

      • 支持tmux 2.4tmux 2.4atmux 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'
      

      【讨论】:

        【解决方案10】:

        较新版本的 tmux 支持更简洁的 if 条件。以下适用于 tmux 3.2a 版:

        if-shell '[ "$(tmux -V)" = "tmux 3.2a" ]' {
            set -g status-bg red
            set -g status-fg yellow
        }
        

        【讨论】:

          【解决方案11】:

          我已将建议的解决方案组合成一个可行的解决方案(在 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"
          

          【讨论】:

          • 您的 cut 命令在不同的版本字符串中可能不够健壮。例如tmux -V at the HEAD of the repo is tmux next-3.3tmux -V | cut -c 6-next-3.3。此外,正如其他人指出的那样,[[ ]] 测试结构是一个 bash 功能,不能跨系统移植,因为唯一有保证的 shell 是符合 POSIX 的sh
          【解决方案12】:

          这不是替代方案,而是对已接受答案的扩展 - (Tom Hale 的答案是最可靠和最完整的)。

          为了减少 .tmux.conf 中的重复次数,您可以将 shell 测试字符串存储在 tmux 环境变量 (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
          
          

          【讨论】:

          • set -g mouse(没有开或关)自行切换。试试这个:bind-key c-M set-option -g mouse \; display-message 'Mouse #{?mouse,on,off}'
          • 我可以更改答案以反映不同的方法,但它与答案无关,它是一个以评估插值语句的if-shell 语句为条件的绑定示例。
          【解决方案13】:

          tmux 3.0a

          # execute a tmux command if a shell-command succeeded
          # if-shell '[[ -z "$SSH_CLIENT" ]]' \     # use test or [ , instead of [[
          # if-shell "[ $HOST == 'redmi14-leo' ]"   # can't work don't know why
          
          if-shell '[[ -z "$SSH_CLIENT" ]]' \
              'source-file ~/.tmux.remote.conf'
          

          【讨论】:

            猜你喜欢
            • 2010-10-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-22
            • 1970-01-01
            • 1970-01-01
            • 2019-06-10
            • 1970-01-01
            相关资源
            最近更新 更多