上一篇文章,我已经把基础的 Clash 终端使用方式打通了:

  • 知道了为什么 curl --proxy 能通,而普通命令不一定会自动走代理;
  • 学会了通过 API 查节点、切节点、看出口;
  • 也写了 clash-node.sh 和 clash-select.sh 这类小脚本。

但是继续用下去之后,我发现还有一个更实际的问题:

能用是一回事,好不好用是另一回事。

如果每次都要手动做下面这些事:

  • 先确认 7890/7891/9090 有没有监听
  • 再决定要不要启动 Clash
  • 再导出环境变量
  • 再测 Google
  • 再查当前节点
  • 再切换策略组
  • 再看出口国家

那终端代理工作流仍然很碎。

所以我又往前走了一步:把这些常用操作统一成一个入口——cx。

这篇文章就记录这套“终端代理工作流”的整理过程,重点是:

  1. 为什么我不想再手动敲一堆 curl + jq + export
  2. 如何把 Clash 的日常操作统一成一个命令前缀
  3. cx start / on / test / current / list / switch / select / country / off 分别负责什么
  4. 为什么这种方式特别适合远程开发、服务器终端、AI 工具安装这类场景

这篇不再重复上一篇里关于代理原理、TUN、基础脚本的内容,而更聚焦于:

如何把这些能力组织成一套真正可长期使用的终端工作流。


关键结论先行

当你把 Clash 的日常操作封装成统一入口(例如 cx)时,重点不在于命令更短,而在于把不同“层级”的状态拆开检查:环境变量层(当前 shell 是否默认走代理)、服务/端口层(7890/7891/9090 是否存在)、控制层(策略组/节点状态),以及验证层(实际出口是否符合预期)。

前置条件

  1. Clash/Mihomo 服务可用,且本地端口可监听:
    • 7890(HTTP)
    • 7891(SOCKS5)
    • 9090(external controller / API)
  2. 你能通过 API 查询 /proxies(并可调用相应更新接口)。
  3. 你至少具备 curl 与 jq;如果你使用 cx on/off,还需要在当前 shell 中能执行对应函数/脚本。

可复现步骤(建议顺序)

  1. cx start:确保服务启动与端口就绪。
  2. cx on:为当前 shell 设置代理环境变量。
  3. cx test:用同一套验证动作确认代理链路可用。
  4. cx current + cx country:确认当前策略选择与实际出口。
  5. 需要变更时使用 cx select / cx switch。
  6. 当前 shell 不再需要默认走代理时执行 cx off;不需要服务时执行 cx stop。

常见误解与纠正(本文后续关联)

如果你观察到“关了当前 shell 的代理(cx off)但端口/节点查询仍可用”,通常是层级差异导致的现象;更彻底的关闭需要停服务(例如 cx stop)。

一、为什么我需要一个统一入口

在终端里使用 Clash,单个动作其实都不难。

例如:

查看监听端口

1
ss -lntp | grep -E '7890|7891|9090'

导出代理环境变量

1
2
3
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export ALL_PROXY=socks5h://127.0.0.1:7891

查看当前节点

1
curl -s http://127.0.0.1:9090/proxies | jq -r '.proxies["🔰 选择节点"].now'

查看当前出口国家

1
curl -s --proxy http://127.0.0.1:7890 https://api.ip.sb/geoip | jq

切换节点

1
curl -s -X PUT 'http://127.0.0.1:9090/proxies/...'   -H 'Content-Type: application/json'   -d '{"name":"🇺🇲 美国Z02"}'

这些命令都能工作,但问题是:

  • 太散
  • 太长
  • 不适合频繁操作
  • 不利于记忆
  • 一旦环境变量、策略组、端口、路径稍有变化,就得重新改

所以我想要的不是“再记住几条命令”,而是:

给 Clash 终端工作流做一个统一的人机接口。

于是我把所有常用操作都归到 cx 下面。


二、我最后整理出来的工作流目标

我希望做到的是:

  • 在任意目录里都能用
  • 不需要每次去记原始 API 路径
  • 不需要手动敲 curl + jq
  • 节点切换要尽量低成本
  • 既能管当前 shell 代理,又能管 Clash 后台服务
  • 能快速判断“到底是环境变量问题、端口问题,还是节点问题”

最后我整理出的目标命令集大概是这样:

1
2
3
4
5
6
7
8
9
10
11
cx start
cx ports
cx on
cx test
cx current
cx list
cx switch "日本Z02"
cx select
cx country
cx off
cx stop

这套命令如果能跑通,终端代理这件事基本就从“能用”变成“好用”了。

验证方式对照(按层定位)

需要确认的点 建议命令 关注点
服务是否在运行 cx ports 或 cx start 7890/7891/9090 是否在监听
当前 shell 是否默认走代理 cx on/off(也可结合 `env grep -i proxy`)
代理链路是否可用、出口是否正常 cx test 用代理发请求并解析出口信息
策略层选择与出口是否一致 cx current + cx country /proxies 的 now 与出口 IP/国家等是否匹配
flowchart TD
  ShellLayer["Shell环境变量层(cx on/off)"] -->|"决定默认代理是否生效"| ShellState["默认走不走代理"]
  ServiceLayer["服务/端口层(cx start/stop/ports)"] -->|"决定端口是否存在"| ServiceState["7890/7891/9090是否可用"]
  ControlLayer["控制层/API(/proxies)"] -->|"cx current/list/switch/select"| ControlState["节点/策略选择结果"]
  ShellState --> ValidationLayer["验证层(cx test/country)"]
  ServiceState --> ValidationLayer
  ControlState --> ValidationLayer
  ValidationLayer --> Outcome["出口与请求是否符合预期"]

三、cx 这套工作流到底解决了什么问题

0. 两层实现思路(底层脚本 + shell 函数)

很多人把“能切节点、能测连通”理解为同一件事,但在终端里做长期工作流时,往往更需要把职责拆开:

  • 底层执行逻辑:负责检查本地监听端口、启动/停止 Clash/Mihomo、访问 external controller 的 API(如 /proxies)、以及执行连通性/出口验证。
  • shell 入口函数(例如在 ~/.bashrc 里定义 cx()):提供统一的人机接口;其中 cx on/off 主要完成当前 shell 的环境变量设置/清理,其余命令把请求转交给底层执行逻辑。

这种分层方式的直接收益是:当出现“某一步看起来没生效”时,可以更快定位到底是环境变量层、服务/端口层,还是策略/API 层的问题。

1. 解决“启动”和“开代理”是两回事

以前常见的误区是:

  • 以为 export http_proxy=... 就等于代理已经启动
  • 或者以为 Clash 启动了,终端就会自动走代理

后来我专门把这两层拆开:

cx start

只负责启动 Clash/Mihomo 后台服务,确认 7890/7891/9090 在监听。

cx on

只负责给当前 shell 设置代理环境变量,让这个终端默认走代理。

也就是说,正确顺序变成了:

1
2
cx start
cx on

这样逻辑上清晰很多。


2. 解决“代理到底有没有生效”难以判断的问题

很多时候我们说“代理没生效”,其实根本没说明白是哪一层没生效。

所以我把验证动作统一成:

1
cx test

它会同时检查:

  • 当前 shell 环境变量是什么
  • 本地 7890/7891/9090 是否在监听
  • 通过 7890 发请求能否成功访问 Google
  • 当前出口 IP 是什么

这就让原本分散的排查动作,一下收敛成了一个入口。


3. 解决“节点切换太麻烦”的问题

原始 API 切换方式没问题,但手感很差。

我当时最烦的地方有两个:

  • 节点名称必须写完整,包括国旗和空格
  • 节点一多,就很容易输错

所以我把它拆成三种使用方式:

查看当前节点

1
cx current

列出所有节点

1
cx list

按关键词切换

1
cx switch "美国Z02"

交互式编号切换

1
cx select

image-20260319091941033

其中 cx select 是我经常使用的方式,它更接近“菜单式操作”。


四、这套工作流的完整使用顺序

我现在基本固定成下面这个顺序。

flowchart TD
  A["cx start"] --> B["cx on"]
  B --> C["cx test"]
  C --> D["cx current"]
  D --> E["cx select/switch"]
  E --> F["cx country"]
  F --> G["cx off"]
  G --> H["cx stop"]

1. 开始工作前:确认服务起来了

1
cx start

这一步的目标不是“开代理”,而是确认:

  • Clash 进程存在
  • 7890/7891/9090 真在监听
  • 日志没有明显报错

如果需要,我还会补一句:

1
cx ports

image-20260319092012975


2. 给当前终端开启默认代理

1
cx on

这一步之后,当前 shell 里的很多命令都会默认走代理,例如:

1
2
3
curl -I https://www.google.com
git ls-remote https://github.com/git/git.git | head
pip install requests

这一步只影响当前终端,不影响别的终端窗口。


3. 立刻做一次连通性确认

1
cx test

image-20260319092033825

建议把这一步作为日常动作使用,因为它可以用于判断:

  • 端口在不在
  • 环境变量在不在
  • Google 通不通
  • 出口 IP 是什么

很多“我感觉代理没开”的误判,都是因为缺了这个统一测试动作。


4. 看当前出口到底走哪

1
2
cx current
cx country

image-20260319092058691

这两个命令组合后,可以更快确认当前选择与实际出口。

  • cx current 告诉你策略组现在选中了哪个节点
  • cx country 告诉你这个节点实际的出口国家、地区、IP、组织

这一步特别适合防止“节点名字和实际出口不一致”的情况。


5. 如果当前节点不满意,就切换

快速模糊切换

1
cx switch "日本Z02"

交互式切换

1
cx select

节点较多时,我更倾向于使用 cx select。

切完之后,一般再补一句:

1
2
cx current
cx country

确保真的切到了想要的出口。


6. 不需要当前终端默认代理时,关掉环境变量

1
cx off

这一步只影响当前 shell 默认代理,不会把 Clash 后台服务停掉。


7. 真正不需要 Clash 时,再停服务

1
cx stop

这时端口才会真的消失。


五、cx 这套工作流常见的价值

1. 它把“代理是一组状态”这件事讲清楚了

以前终端里用 Clash,最容易混淆的是三件事:

  • 当前 shell 有没有默认代理环境变量
  • Clash 后台服务有没有启动
  • 当前策略组到底选了哪个节点

这三件事本来就在不同层:

  • shell 层
  • 服务层
  • API/策略层

cx 的好处就是把它们拆开了:

  • cx on / off 管 shell
  • cx start / stop / ports 管服务
  • cx current / list / switch / select 管策略
  • cx test / country 管验证

这样一拆,日常使用就清爽很多。


2. 它特别适合服务器场景

如果你是在本地桌面上用图形客户端,很多动作可以点鼠标完成。

但在 Linux 服务器、Remote-SSH、远程开发环境里,你需要的是:

  • 纯终端
  • 低依赖
  • 可脚本化
  • 可重复执行
  • 尽量少记忆复杂命令

这就是为什么我觉得 cx 这种统一入口,在服务器上特别有价值。


3. 它让“排查问题”也统一了

以前排查一个代理问题,可能要连续做这些动作:

1
2
3
4
ss -lntp | grep ...
env | grep -i proxy
curl --proxy ...
curl http://127.0.0.1:9090/...

现在大多数情况下我只要先跑:

1
2
3
cx ports
cx test
cx current

就能很快判断出问题大概在哪一层。


六、cx 这套工作流特别适合什么场景

在长期使用后,我发现它适用于下面这些场景:

1. AI 工具安装与登录前的环境准备

例如:

  • Claude Code
  • Codex CLI
  • npm 全局工具
  • pip 安装包
  • GitHub 拉取代码

这些操作依赖你是否能稳定让当前终端走代理。

2. 远程 SSH / VS Code Remote-SSH

这种场景下,图形化代理客户端的作用相对有限,通常还需要靠终端里的代理控制。

3. 节点很多,需要频繁切换出口

尤其是:

  • 日本 / 美国 / 香港 / 新加坡
  • 有 IEPL、下载专用、低倍率节点
  • 需要快速试不同节点效果

这时候 cx list + cx select + cx country 的组合更省事。

4. 想做长期维护,而不是临时拼凑几条命令

一旦你开始长期用服务器,代理这件事就不该还是靠零散命令维持。


七、我常用的一组命令

如果只保留常用的一组,我现在基本就记这几个:

1
2
3
4
5
6
7
8
cx start
cx on
cx test
cx current
cx select
cx country
cx off
cx stop

大多数日常使用都能覆盖到。

如果再缩成“最小日常工作流”,就是:

1
2
3
4
5
cx start
cx on
cx test
cx select
cx country

八、我对这套工作流的一个总结

前一篇文章更多是在回答:

Clash 在 Linux 上到底怎么用顺?

而这一篇更像是在回答:

当这些基础动作都能跑通之后,怎么把它们整理成一套真正可长期使用的终端习惯?

对我来说,cx 的主要意义不是“又发明了一个命令缩写”,而是:

把 Clash 在 Linux 终端里的日常使用整理成了一套一致且便于维护的工作流。

它的价值主要在于三点:

  1. 把原本分散的命令统一到一个入口
  2. 把“启动、开代理、切节点、测试、验证”串成一个自然流程
  3. 让以后每次新开终端、新上服务器时,都能迅速恢复到熟悉的节奏

总结

如果你也在 Linux 服务器、远程开发、AI 工具安装、GitHub 访问、节点切换这些场景下长期使用 Clash,我很建议你不要只停留在“会敲几条命令”的阶段,而是把这些动作沉淀成一套自己的工作流。

对我来说,这套工作流最终就收敛成了一个前缀:

1
cx

看起来很小,但它背后其实把:

  • 当前 shell 代理
  • Clash 后台服务
  • 本地 API
  • 节点管理
  • 出口验证

全部串了起来。

当这些动作都被统一之后,终端代理这件事就不再是“麻烦但不得不做的前置准备”,而会慢慢变成一种很自然的基础设施能力。