Как написать инструкцию if в .tmux.conf для установки разных опций для разных версий 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

Ответы

Ответ 1

Основываясь на ответах @ericx и @thiagowfx, я собрал следующее, охватывающее многие из перечисленных несовместимостей начиная с версии 2.0:

# 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 здесь. В итоге разработчики tmux не будут поддерживать обратную совместимость и не будут использовать схему нумерации версий, которая указывает, какие версии содержат критические изменения. 😢

Я поднял вопрос о поддержке числовых компараторов для %if это было реализовано в v3.0.

Ответ 2

if-shell не всегда работает. Вместо этого я использую оболочку script для загрузки правильной версии 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

Ответ 3

Это своего рода суета. Правильный способ сделать это в tmux (не полагаясь на скрипт внешней оболочки) сочетает в себе функции ответов Vincent и jdloft.

Команда if-shell в tmux используется как

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).

Обратите внимание, что расширение ommand shell -c ommand будет расширять переменные вида #{pane_current_path} но в противном случае команда останется одна.

Что еще более важно, обратите внимание, что tmux использует /bin/sh -c для выполнения указанной нами команды оболочки. Таким образом, команда должна быть POSIX-совместимой, поэтому тесты вида [[ не гарантированно переносимы. Современные системы Ubuntu и Debian, например, symlink /bin/sh to dash.

Мы хотим запустить POSIX-совместимую команду оболочки, которая проверяет версию 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. Кроме того, нет необходимости в конструкции if/then/else/fi, так как оператор [ создает истинное значение.

Пара заметок

  • Строки, продолжающиеся на следующую строку, не могут иметь завершающих комментариев, иначе tmux выдаст сообщение об ошибке "неизвестная команда".
  • "Команда, если ложь" может быть опущена.
  • Несколько команд для true или false могут быть объединены с использованием ;
  • Команда запускается в базовой оболочке с помощью /bin/sh -c. Другие подходы, которые используют [[ или другой синтаксис не-POSIX, не гарантированно работают.

РЕДАКТИРОВАТЬ: предыдущая версия этого ответа использовала [[, который не работает в системах, которые не используют bash. Замена на [ решает это.

Ответ 4

Я также наткнулся на несоответствия конфигурации в разных версиях tmux. Просмотрев все решения здесь и этот связанный вопрос на 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, но:

  • Для него не требуется внешняя оболочка script.
  • Он не разделяется на диапазоны фиксированной версии (.../1.9 до 2.0/2.1...). Вместо этого можно использовать (sym) ссылки для совместного использования фрагмента конфигурации из нескольких версий tmux.
  • Он не содержит жесткого кода для одного имени файла для версии. Предоставляя несколько фрагментов конфигурации для каждой версии, части могут быть разделены между версиями, в то время как другие поддерживаются версией. Это должно обеспечить максимальную гибкость.
  • В исходном ~/.tmux.conf имеется только один элемент конфигурации. Другие решения, такие как один из @TomHale, дублируют проверку версии для каждого элемента конфигурации.

Ответ 5

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'

Ответ 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 ;"

Ответ 7

Я объединил предложенные решения с рабочим (протестировано на 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"

Ответ 8

Текущий последний выпуск - 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"