Zellij 脚本编程与程序化控制

前文介绍了 zellij action 的各种子命令,本文将进入脚本编程的领域。通过 subscribe 实时监控面板事件、watch 只读监视会话,以及将 action 命令组合成完整的自动化脚本,你可以让 Zellij 成为 CI 流水线、多步骤工作流和后台任务管理的强大平台。

一、zellij subscribe 实时监控

zellij subscribe 是 Zellij 脚本编程的核心工具,它可以实时输出面板的事件流,包括终端输出、退出事件、焦点变化等。

基本用法

zellij subscribe --pane-id <面板ID> <事件类型>

监控指定面板的终端输出:

zellij subscribe --pane-id 1 terminal_1

这会持续输出面板 1 的所有终端数据(包括 ANSI 转义序列),直到你手动中断。

选项

选项说明
-p / --pane-id <id>指定要监控的面板 ID
-s / --session-name <名称>指定目标会话名称
-f / --history包含历史输出(从面板创建开始的完整输出)
--ansi保留 ANSI 转义序列(默认会剥离)

JSON 输出模式与 jq 过滤

subscribe 的输出可以配合 jq 进行结构化过滤:

# 监控面板输出并过滤 JSON
zellij subscribe --pane-id 1 terminal_1 | \
  jq -r '.data' | grep "ERROR"

# 只提取退出事件
zellij subscribe --pane-id 1 pane_exited | \
  jq -r '.exit_status'

常用的事件类型包括:

  • terminal_1:面板的终端输出流
  • pane_exited:面板中进程退出的通知
  • focus:面板获得或失去焦点

监控其他会话和多个面板

使用 -s 选项可以监控其他会话中的面板:

zellij subscribe -s ci-session --pane-id 3 terminal_1

要同时监控多个面板,可以在后台运行多个 subscribe 进程:

#!/bin/bash
zellij subscribe --pane-id 1 terminal_1 > /tmp/pane1.log &
zellij subscribe --pane-id 2 terminal_1 > /tmp/pane2.log &
wait

二、zellij watch 只读监视

zellij watch 提供了一种更简单的只读监视方式,可以直接查看指定会话的实时状态:

zellij watch my-session-name

这个命令会以只读方式连接到指定会话,你可以看到面板的实时输出,但不能进行任何操作。它非常适合在不干扰工作流的情况下查看 CI 构建进度或监控后台任务。

三、脚本编程实例

CI 流水线脚本

以下脚本演示如何用 Zellij 构建一个简单的 CI 流水线:在一个会话中依次运行构建、测试、部署,并根据每一步的结果决定是否继续:

#!/bin/bash
set -euo pipefail

SESSION="ci-pipeline"
zellij -s "$SESSION" -d  # 创建分离会话

# 第一步:构建
zellij action -s "$SESSION" run -n "构建" --blocking -- cargo build --release
if [ $? -ne 0 ]; then
    echo "构建失败,终止流水线"
    zellij kill-session "$SESSION"
    exit 1
fi

# 第二步:测试
zellij action -s "$SESSION" run -n "测试" --blocking -- cargo test
if [ $? -ne 0 ]; then
    echo "测试失败,终止流水线"
    zellij kill-session "$SESSION"
    exit 1
fi

# 第三步:部署
zellij action -s "$SESSION" run -n "部署" --blocking -- ./deploy.sh
echo "流水线执行完毕"

# 保存会话并分离
zellij kill-session "$SESSION"

多步骤人工干预工作流

有些工作流需要人工确认后才能继续。以下脚本创建一个面板等待用户输入,然后根据输入决定下一步操作:

#!/bin/bash
set -euo pipefail

SESSION="deploy-workflow"
zellij -s "$SESSION" -d

# 在面板中显示部署信息,等待用户确认
zellij action -s "$SESSION" run -n "确认部署" -- \
  bash -c 'read -p "确认部署到生产环境?(y/N): " confirm; \
           [ "$confirm" = "y" ] && echo "CONFIRMED" || echo "CANCELLED"'

# 等待并检查输出
sleep 2
OUTPUT=$(zellij action -s "$SESSION" dump-screen)
if echo "$OUTPUT" | grep -q "CONFIRMED"; then
    zellij action -s "$SESSION" run -n "部署中" -- ./deploy-prod.sh
else
    echo "部署已取消"
    zellij kill-session "$SESSION"
    exit 0
fi

Git 状态覆盖面板

使用浮动面板在屏幕角落显示实时 Git 状态:

#!/bin/bash
# git-overlay.sh — 在浮动面板中显示 Git 状态

zellij run -f \
  --x "75%" --y "65%" \
  --width "25%" --height "30%" \
  -n "Git Status" \
  -- bash -c 'while true; do
    clear
    echo "=== Git Status ==="
    echo ""
    git status -s
    echo ""
    echo "=== Recent Commits ==="
    git log --oneline -5
    echo ""
    echo "=== Branch ==="
    git branch -v
    sleep 5
  done'

资源监控覆盖面板

类似的思路,创建一个资源监控浮动面板:

#!/bin/bash
# resource-monitor.sh — 在浮动面板中监控系统资源

zellij run -f \
  --x 0 --y "70%" \
  --width "30%" --height "28%" \
  -n "监控" \
  -- bash -c 'while true; do
    clear
    echo "=== CPU ==="
    top -bn1 | head -3
    echo ""
    echo "=== Memory ==="
    free -h
    echo ""
    echo "=== Disk ==="
    df -h / | tail -1
    sleep 3
  done'

后台任务管理模式

以下脚本展示如何创建一个后台任务管理面板,在后台运行长时间任务并记录日志:

#!/bin/bash
set -euo pipefail

SESSION="tasks"
LOG_DIR="/tmp/zellij-tasks"
mkdir -p "$LOG_DIR"

# 创建会话
zellij -s "$SESSION" -d

# 后台任务 1:编译
zellij action -s "$SESSION" run -n "编译" -- \
  bash -c 'cargo build --release 2>&1 | tee /tmp/zellij-tasks/build.log; \
           echo "BUILD_DONE" >> /tmp/zellij-tasks/build.log'

# 后台任务 2:文档生成
zellij action -s "$SESSION" run -n "文档" -- \
  bash -c 'cargo doc --no-deps 2>&1 | tee /tmp/zellij-tasks/doc.log; \
           echo "DOC_DONE" >> /tmp/zellij-tasks/doc.log'

# 后台任务 3:代码检查
zellij action -s "$SESSION" run -n "检查" -- \
  bash -c 'cargo clippy 2>&1 | tee /tmp/zellij-tasks/clippy.log; \
           echo "CLIPPY_DONE" >> /tmp/zellij-tasks/clippy.log'

echo "所有后台任务已启动,会话名: $SESSION"
echo "查看进度: zellij attach $SESSION"
echo "查看日志: cat $LOG_DIR/*.log"

四、程序化控制

控制面概览

Zellij 的程序化控制可以分为四个维度:

  • 查询:获取会话、面板、标签页的当前状态。对应命令:list-paneslist-tabscurrent-tab-infodump-screen
  • 变更:创建、关闭、修改面板和标签页。对应命令:new-paneclose-panesend-keysrunedit
  • 观察:持续监听面板事件和输出。对应命令:subscribewatch
  • 阻塞:等待某个条件满足后继续。对应命令:--blocking--block-until-exit-success--block-until-exit-failure

控制循环模式

大多数 Zellij 脚本遵循相同的控制循环模式:

创建会话 → 打开面板 → 发送命令 → 观察输出 → 反应 → 重复

具体来说:

  1. 创建会话zellij -s my-session -d 创建一个分离会话
  2. 打开面板zellij action -s my-session run -- cmd 在会话中运行命令
  3. 发送命令zellij action send-keys --pane-id N "input" Enter
  4. 观察输出:通过 dump-screensubscribe 获取面板内容
  5. 反应:根据输出内容执行不同的操作分支

等待输出条件

在脚本中等待面板输出满足特定条件有四种主要方法:

方法一:阻塞面板(最可靠)

# 阻塞等待命令完成
zellij action run --blocking -- cargo build
echo "构建完成"

方法二:轮询 dump-screen(最灵活)

# 轮询等待特定字符串出现
wait_for_output() {
    local pane_id=$1
    local pattern=$2
    local max_wait=$3
    local elapsed=0

    while [ $elapsed -lt $max_wait ]; do
        OUTPUT=$(zellij action dump-screen)
        if echo "$OUTPUT" | grep -q "$pattern"; then
            return 0
        fi
        sleep 1
        elapsed=$((elapsed + 1))
    done
    return 1
}

wait_for_output 1 "BUILD SUCCESSFUL" 120

方法三:轮询退出状态(最简单)

# 等待面板进程退出
wait_for_exit() {
    local pane_id=$1
    while zellij action list-panes | grep -q "id: $pane_id"; do
        sleep 1
    done
}

方法四:subscribe 流式观察(最实时)

# 流式监控面板输出
zellij subscribe --pane-id 1 terminal_1 | \
  jq -r '.data' | \
  while IFS= read -r line; do
    if echo "$line" | grep -q "DONE"; then
        echo "任务完成"
        break
    fi
  done

快照与流式观察的选择

dump-screen(快照)和 subscribe(流式)各有适用场景:

方式优点缺点适用场景
dump-screen简单直观,获取完整屏幕内容需要轮询,可能错过短暂输出一次性检查、简单条件等待
subscribe实时获取所有输出,不会遗漏输出量大,需要持续处理流式日志分析、实时事件响应

结构化输出参考

以下命令支持 JSON 结构化输出,方便脚本解析:

  • zellij action list-panes:输出所有面板的 ID、名称、尺寸等信息
  • zellij action list-tabs:输出所有标签页的索引、名称、面板列表
  • zellij action current-tab-info:输出当前标签页的详细信息
  • zellij subscribe:输出面板事件的 JSON 流
  • zellij action dump-screen:输出面板的纯文本屏幕内容
  • zellij list-sessions:列出所有会话及其状态

并发与顺序

默认情况下,多个 zellij action 命令可以并发执行。例如同时启动多个面板运行不同任务:

# 并发启动多个任务
zellij action run -n "构建" -- cargo build &
zellij action run -n "测试" -- cargo test &
zellij action run -n "检查" -- cargo clippy &
wait
echo "所有任务已启动"

如果需要顺序执行(前一个完成后再执行下一个),使用 --blocking 选项:

# 顺序执行:构建 → 测试 → 部署
zellij action run --blocking -- cargo build || exit 1
zellij action run --blocking -- cargo test || exit 1
zellij action run --blocking -- ./deploy.sh || exit 1
echo "全部完成"

通过灵活组合并发和顺序执行,你可以构建出从简单到复杂的各种自动化工作流。Zellij 的 CLI 操作 + subscribe/watch 机制,使得终端多路复用器不再只是手动操作的工具,而成为了可编程的自动化平台。

返回博客列表