在我的本地机器上,我有 3 个 node.js 实例同时运行。每个在名为“服务器”的 tmux 窗口中都有自己的 Pane 。问题是找出哪个节点在哪个 Pane 中运行并不容易,因为它们的日志是相似的。

我需要的是每个 Pane 的标题。据我所知,tmux 本身没有这个功能:它只有窗口的标题,而不是 Pane 的标题。在每个 Pane 中为每个 node.js 实例启动一个单独的 tmux session 看起来有点矫枉过正。

那么是否有一些小程序可以启动一个命令,用指定的状态栏包装它的输出?

提前致谢

最佳答案

tmux 确实支持每个 Pane 的标题,但它不提供每个 Pane 的位置来显示这些标题。

您可以使用转义序列 ESC ]2; … ESC \ 设置 Pane 的标题(例如,请参阅 tmux 联机帮助页中名为 Names and Titles 的部分)。您可以像这样从 shell 执行此操作:

printf '\033]2;%s\033\\' 'title goes here'

每个 Pane 的标题默认为系统的主机名。默认情况下,事件 Pane 的标题显示在 tmux 状态行的右侧( session 变量 status-right 的默认全局值为 "#22T" %H:%M %d-%b-%y ,显示 Pane 标题、时间和日期的 22 个字符)。

因此,只要您对能够看到事件 Pane 的标题感到满意(即愿意切换 Pane 以查看非事件 Pane 的标题),您就可以使用默认功能。只需在为每个 Pane 启动主命令之前发送适当的标题设置转义序列。

如果您绝对需要一条专线来显示一些每个 Pane 的信息,那么嵌套的 tmux session 可能不会像您最初想象的那样(不必要)“过度杀伤”。

在一般情况下,要在某些给定终端上提供不受侵犯的状态行,您将需要一个完整的终端(重新)仿真器,它位于原始终端和新终端(少一个行)之间。需要这种(重新)仿真来转换发送到内部终端的控制序列并将它们转换为原始终端。例如,要在外部终端的底部维护一个状态行,命令



发送到内部终端必须成为



当翻译并发送到外部终端时。同样,发送到内部终端的 LF 必须变成



在外部终端。

像 tmux 和 screen 这样的程序就是这样的终端重新仿真器。当然,终端仿真器还包含许多其他功能,但是您需要大量的终端仿真代码才能提供可靠的状态行。

然而,有一个轻量级的解决方案,只要
  • 您的程序(Node.js 实例)与运行它们的 Pane 的终端交互有限(即没有光标定位),以及
  • 在程序运行时不要调整 Pane 的大小。

  • 像许多终端模拟器一样,tmux 在其 Pane 中支持“设置滚动区域”终端控制命令。您可以使用此命令将滚动区域限制在终端的顶部(或底部)N-1 行,并将某种实例标识文本写入非滚动行。

    需要限制(不允许光标移动命令,不允许调整大小),因为生成输出的程序(例如 Node.js 实例)不知道滚动已被限制在特定区域。如果输出生成程序碰巧将光标移到滚动区域之外,则输出可能会出现乱码。同样,终端模拟器可能会在调整终端大小时自动重置滚动区域(因此“非滚动行”可能最终会滚动消失)。

    我写了一个脚本,使用tput生成相应的控制序列,写入非滚动行,将光标移动到滚动区域后运行一个程序:
    #!/bin/sh
    
    # usage: no_scroll_line top|bottom 'non-scrolling line content' command to run with args
    #
    #     Set up a non-scrolling line at the top (or the bottom) of the
    #     terminal, write the given text into it, then (in the scrolling
    #     region) run the given command with its arguments. When the
    #     command has finished, pause with a prompt and reset the
    #     scrolling region.
    
    get_size() {
        set -- $(stty size)
        LINES=$1
        COLUMNS=$2
    }
    set_nonscrolling_line() {
        get_size
        case "$1" in
            t|to|top)
                non_scroll_line=0
                first_scrolling_line=1
                scroll_region="1 $(($LINES - 1))"
                ;;
            b|bo|bot|bott|botto|bottom)
                first_scrolling_line=0
                scroll_region="0 $(($LINES - 2))"
                non_scroll_line="$(($LINES - 1))"
                ;;
            *)
                echo 'error: first argument must be "top" or "bottom"'
                exit 1
                ;;
        esac
        clear
        tput csr $scroll_region
        tput cup "$non_scroll_line" 0
        printf %s "$2"
        tput cup "$first_scrolling_line" 0
    }
    reset_scrolling() {
        get_size
        clear
        tput csr 0 $(($LINES - 1))
    }
    
    # Set up the scrolling region and write into the non-scrolling line
    set_nonscrolling_line "$1" "$2"
    shift 2
    
    # Run something that writes into the scolling region
    "$@"
    ec=$?
    
    # Reset the scrolling region
    printf %s 'Press ENTER to reset scrolling (will clear screen)'
    read a_line
    reset_scrolling
    
    exit "$ec"
    

    你可以这样使用它:
    tmux split-window '/path/to/no_scroll_line bottom "Node instance foo" node foo.js'
    tmux split-window '/path/to/no_scroll_line bottom "Node instance bar" node bar.js'
    tmux split-window '/path/to/no_scroll_line bottom "Node instance quux" node quux.js'
    

    只要终端支持并发布其 csrcup terminfo 功能,该脚本也应该在 tmux 之外工作。

    关于command-line - Tmux 中的 Pane 标题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9747952/

    10-14 06:19