给 Claude Code 的状态栏整整容:一条命令把模型、花费、Git 状态全塞进去

lxiol
📝
Claude Code 底部那条长长的状态栏一直是空的?我用一个 Bash 脚本把它填满了——模型名、Git 分支、上下文进度条、花费、对话时长,一次全显示。

原文链接:https://mp.weixin.qq.com/s/H15Zq5oSeISsa5G36oU2jw

Claude Code 底部那条长长的状态栏一直是空的?我用一个 Bash 脚本把它填满了——模型名、Git 分支、上下文进度条、花费、对话时长,一次全显示。

前几天用 Claude Code 写代码,写着写着目光落在终端最下面那行。

空的。

那么长一条横栏,什么都没显示。我盯着它看了几秒,突然觉得浪费——我明明可以在这一行里看到当前用的模型、项目路径、Git 分支和改动、上下文窗口用了多少、这轮对话花了多少钱。

这些信息平时我都得切到别的地方才能看到。

去翻官方文档,发现确实有 statusLine 这个功能,可以跑一个自定义脚本,把结果打印在底部状态栏。但文档里只给了一个框架说明,没有完整的例子。配置细节散落在各个 issue 和讨论里。

于是我自己折腾了一套,用下来感觉挺满意。

简单说:Claude Code 的底部有一行可以运行自定义脚本。每次助手返回消息后,Claude Code 会把当前会话的 JSON 数据通过 stdin 喂给这个脚本,脚本负责读 JSON、拼字符串、输出到 stdout。输出内容就显示在状态栏上。

更新频率是每次助手消息后触发,有 300ms 的防抖。所以你不用关心性能问题——它不会每条消息都跑。

脚本能拿到的 JSON 数据大概长这样:

1
2
3
4
5
6
`{
  "model": { "display_name": "Sonnet" },
  "workspace": { "current_dir": "/home/user/my-project" },
  "context_window": { "used_percentage": 45.3 },
  "cost": { "total_cost_usd": 0.38, "total_duration_ms": 612000 }
}`

关键字段:

  • model.display_name —— 当前使用的模型名
  • workspace.current_dir —— 当前工作目录
  • context_window.used_percentage —— 上下文窗口使用百分比
  • cost.total_cost_usd —— 本轮对话的累计花费(美元)
  • cost.total_duration_ms —— 本轮对话的持续时间(毫秒)

其他信息可以通过 shell 命令自己获取,比如 git 状态。

这里有个坑:在第一次 API 调用之前,这些字段可能全部是 null 所以脚本里必须处理空值,否则输出会很难看。

我想要什么

目标很明确:一条状态栏同时显示以下信息:

  • • 当前模型名
  • • 当前目录(只显示最后一段,不要完整路径)
  • • Git 分支 + 暂存区文件数 + 修改文件数
  • • 上下文窗口使用进度条(带颜色预警)
  • • 花费和对话时长

工具选择:Bash + jq。就这两个,不需要装一堆依赖。

完整脚本

~/.claude/statusline.sh 创建脚本文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
`#!/bin/bash
# Claude Code Status Line
# Displays: Model, directory, git status, context usage bar, cost, duration

input=$(cat)

# ── Extract fields from JSON ──
MODEL=$(echo "$input" | jq -r '.model.display_name')
DIR=$(echo "$input" | jq -r '.workspace.current_dir')
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')

# ── Colors ──
CYAN='\033[36m'; GREEN='\033[32m'; YELLOW='\033[33m'; RED='\033[31m'; RESET='\033[0m'

# ── Progress bar with threshold-based color ──
if [ "$PCT" -ge 90 ] 2>/dev/null; then BAR_COLOR="$RED"
elif [ "$PCT" -ge 70 ] 2>/dev/null; then BAR_COLOR="$YELLOW"
else BAR_COLOR="$GREEN"; fi

FILLED=$((PCT / 10)); EMPTY=$((10 - FILLED))
printf -v FILL "%${FILLED}s"; printf -v PAD "%${EMPTY}s"
BAR="${FILL// /█}${PAD// /░}"

# ── Duration formatting ──
MINS=$((DURATION_MS / 60000)); SECS=$(((DURATION_MS % 60000) / 1000))

# ── Git info with 5-second cache ──
CACHE_FILE="/tmp/statusline-git-cache"
CACHE_MAX_AGE=5

cache_is_stale() {
  [ ! -f "$CACHE_FILE" ] || \
  [ $(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0))) -gt $CACHE_MAX_AGE ]
}

if cache_is_stale; then
  if git rev-parse --git-dir > /dev/null 2>&1; then
    BRANCH=$(git branch --show-current 2>/dev/null)
    STAGED=$(git diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ')
    MODIFIED=$(git diff --numstat 2>/dev/null | wc -l | tr -d ' ')
    echo "$BRANCH|$STAGED|$MODIFIED" > "$CACHE_FILE"
  else
    echo "||" > "$CACHE_FILE"
  fi
fi

IFS='|' read -r BRANCH STAGED MODIFIED < "$CACHE_FILE"

# ── Build git status string ──
GIT_INFO=""
if [ -n "$BRANCH" ]; then
  GIT_INFO=" | 🌿 $BRANCH"
  if [ "$STAGED" -gt 0 ] 2>/dev/null; then
    GIT_INFO="${GIT_INFO} ${GREEN}+${STAGED}${RESET}"
  fi
  if [ "$MODIFIED" -gt 0 ] 2>/dev/null; then
    GIT_INFO="${GIT_INFO} ${YELLOW}~${MODIFIED}${RESET}"
  fi
fi

# ── Output (single line) ──
COST_FMT=$(printf '$%.2f' "$COST")
echo -e "${CYAN}[$MODEL]${RESET} 📁 ${DIR##*/}${GIT_INFO} | ${BAR_COLOR}${BAR}${RESET} ${PCT}% | ${YELLOW}${COST_FMT}${RESET} | ⏱️ ${MINS}m ${SECS}s"`

保存后加执行权限:

1
`chmod +x ~/.claude/statusline.sh`

配置 settings.json

编辑 ~/.claude/settings.json,加入 statusLine 配置:

1
2
3
4
5
6
7
`{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 2
  }
}`

padding 控制状态栏左右各留几个空格,2 刚好。

⚠️ 如果 settings.jsondisableAllHooks 设成了 true,status line 脚本是不会跑的。确认它没开。

测试一下

在配置之前,可以先手动测试脚本能不能正常解析数据:

1
`echo '{"model":{"display_name":"Sonnet"},"workspace":{"current_dir":"/home/user/my-project"},"context_window":{"used_percentage":45},"cost":{"total_cost_usd":0.38,"total_duration_ms":612000}}' | ~/.claude/statusline.sh`

应该看到类似这样的输出:

1
`[Sonnet] 📁 my-project | 🌿 main +2 ~1 | ████░░░░░░ 45% | $0.38 | ⏱️ 10m 12s`

颜色在你的终端里应该也会生效:模型名是青色,进度条颜色根据百分比变化,花费是黄色。

几个设计取舍

Git 缓存为什么用固定文件名

我一开始犯的错误是用 $$(进程 PID)做缓存文件名。结果缓存永远不命中。

原因是状态栏脚本每次都是一个新的 shell 进程被启动,PID 每次都不同。用 PID 做文件名等于每次都在写新文件。换成固定的 /tmp/statusline-git-cache 就没这个问题了。

用固定文件名做缓存,5 秒刷新一次。避免每次启动新进程都重新查询 git 状态

为什么缓存 5 秒

太短(1 秒)的话缓存意义不大;太长(15 秒)的话你刚 commit 完状态栏还显示旧的。5 秒是体感比较合适的折中。

进度条的阈值

  • • 低于 70%:绿色
  • • 70%-89%:黄色
  • • 90% 及以上:红色

设成这样是有原因的。当上下文窗口快满的时候,Claude 会开始”遗忘”较早的对话内容。这时候你需要知道——也许该开个新会话了。红色就是提醒你该清上下文了。

used_percentage 只算输入 token

这个百分比只统计输入侧的 token 用量,不算输出。这和 Claude Code 自己的 /context 命令保持一致。所以如果你看到百分比不高但 Claude 开始”忘事”,不一定是 bug,可能是输出 token 也在消耗上下文空间。

// 0 在 jq 里的作用

jq 的 // 是”替代运算符”。当左边的值为 nullfalse 时,返回右边的值。写 // 0 的意思就是”如果这个字段是 null,就用 0 代替”。没有这个 fallback,在第一次 API 调用前输出会是一堆 null 和空字符串,很难看。

常见问题

状态栏什么都不显示?

检查三件事:

    1. 脚本有没有执行权限:ls -l ~/.claude/statusline.sh 看有没有 x
    1. settings.jsondisableAllHooks 是不是 true
    1. jq 有没有装:which jq

值显示 null--

等第一条 API 响应回来。在第一次调用模型之前,JSON 里的字段都是 null,这是正常的。脚本已经用 // 0 做了兜底,至少不会报错。

进度条的方块显示成乱码?

你的终端可能不支持这些 Unicode 字符()。换成 ASCII 替代方案:把脚本里的 改成 # 改成 -

Git 信息不显示?

确认当前目录是 git 仓库(git status 能跑)。不在 git 仓库里的话,脚本会自动跳过 git 部分。

最终效果

跑起来之后,Claude Code 底部的状态栏大概是这个样子:

1
`[Sonnet] 📁 my-project | 🌿 main +2 ~1 | ████░░░░░░ 45% | $0.38 | ⏱️ 10m 12s`

从左到右:模型名、项目目录、Git 分支和改动、上下文进度条、花费、对话时长——一条状态栏全搞定

每个部分从左到右:

  • [Sonnet] —— 当前模型,青色
  • 📁 my-project —— 项目目录名(不是完整路径)
  • 🌿 main +2 ~1 —— Git 分支,绿色 +2 表示暂存区 2 个文件,黄色 ~1 表示工作区 1 个文件已修改
  • ████░░░░░░ 45% —— 上下文使用进度条,颜色随阈值变化
  • $0.38 —— 累计花费,黄色
  • ⏱️ 10m 12s —— 对话时长

花几分钟配一次,之后每次用 Claude Code 都能一低头看到所有关键信息。对我来说,最值得的部分其实是花费和上下文进度条——以前这两样得手动查,现在余光扫一眼就知道。

脚本已开源: 可以直接复制上面的脚本使用,或者根据你的需求调整。


💬 本文评论区已开启,但暂无读者留言。

本文转载自微信公众号,如有侵权请联系删除。

  • 标题: 给 Claude Code 的状态栏整整容:一条命令把模型、花费、Git 状态全塞进去
  • 作者: lxiol
  • 创建于 : 2026-04-29 20:26:21
  • 更新于 : 2026-05-12 16:32:44
  • 链接: https://blog.lxiol.cn/2026/04/29/给-Claude-Code-的状态栏整整容一条命令把模型花费Git-状态全塞进去/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。