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

  • 知道了为什么 curl --proxy 能通,而普通命令不一定会自动走代理;
  • 学会了通过 API 查节点、切节点、看出口;
  • 也写了 clash-node.shclash-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. 你至少具备 curljq;如果你使用 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 portscx start 7890/7891/9090 是否在监听
当前 shell 是否默认走代理 cx on/off(也可结合 `env grep -i proxy`)
代理链路是否可用、出口是否正常 cx test 用代理发请求并解析出口信息
策略层选择与出口是否一致 cx current + cx country /proxiesnow 与出口 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
  • 节点管理
  • 出口验证

全部串了起来。

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