命令行美化(pgcli)
pgcli 是一个基于 Python 的 PostgreSQL 交互式命令行客户端(Interactive Terminal Client),在保留 psql 使用习惯的同时,补上了 psql 缺失的语法高亮、智能补全与多行编辑。本节将介绍 pgcli 与 psql 的差异、安装方式、配置文件、补全能力与局限。
前置知识
阅读本节前,建议先了解:Navicat / DataGrip
基础概念
psql 是官方客户端,功能最全、行为最稳定,但它的交互体验停留在「纯文本终端」时代:没有语法着色,补全依赖手写查询,长 SQL 编辑不便。
pgcli 的思路是只重做交互层,不动协议层:
- 底层仍通过 libpq(Python 侧的
psycopg)连接 PostgreSQL,行为与 psql 一致 - 上层用 Python 的提示工具包(prompt_toolkit)重写输入区,实现实时补全与语法高亮
- 元命令(Meta-Command)尽可能兼容 psql,
\d、\dt、\x、\timing等仍可用
理解这一点很重要:pgcli 不是 psql 的替代品,而是 psql 的「编辑器增强版」。写脚本、做批处理仍应使用 psql;交互式探索、编写复杂查询时 pgcli 更舒服。
| 术语 | 英文名 | 说明 |
|---|---|---|
| 语法高亮 | Syntax Highlighting | 按词法给 SQL 关键字、字符串、标识符着色 |
| 智能补全 | Smart Completion | 基于数据库元数据补全表名、列名、函数、关键字 |
| 多行模式 | Multi-line Mode | 允许回车换行而非立即执行,便于编辑长 SQL |
| 模糊匹配 | Fuzzy Matching | 输入片段即可匹配,如 usod 匹配 user_orders |
| 提示工具包 | prompt_toolkit | pgcli 依赖的终端交互库 |
| 包装器 | Wrapper | pgcli 对 psql 元命令的兼容实现 |
安装与配置
安装方式对比
| 方式 | 命令 | 隔离性 | 适用场景 |
|---|---|---|---|
| pipx | pipx install pgcli | 高(独立虚拟环境) | 推荐的通用方式 |
| pip | pip install --user pgcli | 低(污染用户环境) | 已有虚拟环境管理习惯 |
| Homebrew | brew install pgcli | 中(brew 托管) | macOS 用户最省事 |
| apt | sudo apt install pgcli | 中 | Debian/Ubuntu 快速安装 |
| Docker | docker run ... pgcli | 完全隔离 | 不想在宿主机装 Python 依赖 |
bash
# ── 推荐:pipx(Python 3.9+)──
python3 -m pip install --user pipx
python3 -m pipx ensurepath
pipx install pgcli
# 升级
pipx upgrade pgcli
# ── macOS:Homebrew ──
brew install pgcli
# ── Debian / Ubuntu ──
sudo apt update && sudo apt install -y pgcli
# ── Windows:scoop ──
scoop install pgclibash
# 验证安装:查看版本与依赖的驱动
pgcli --version
# pgcli 4.x
# psycopg 3.x
# 确认 pgcli 找到了 psql 的元命令后端(部分功能依赖本地 psql)
which psql
psql --version连接方式
pgcli 的连接参数与 psql 高度一致,支持短选项、长选项、DSN 与环境变量:
bash
# 短选项
pgcli -h 127.0.0.1 -p 5432 -U app_user -d demo
# 长选项
pgcli --host=127.0.0.1 --port=5432 --user=app_user --dbname=demo
# DSN(同 libpq 格式,可直接粘贴 psql 的连接串)
pgcli "postgresql://app_user:secret@127.0.0.1:5432/demo?sslmode=require"
# 只传库名,其余从环境变量读取
PGHOST=127.0.0.1 PGUSER=app_user PGPASSWORD=secret pgcli demo
# 复用 psql 的服务定义(~/.pg_service.conf)
pgcli service=demodbtext
# ~/.pg_service.conf(psql 与 pgcli 共用)
[demodb]
host=127.0.0.1
port=5432
dbname=demo
user=app_user
sslmode=require配置文件
pgcli 的主配置文件位于 ~/.config/pgcli/config(Windows 为 %USERPROFILE%\AppData\Local\pgcli\config):
ini
# ~/.config/pgcli/config
[main]
# 多行模式:safe 表示仅当语句以分号结尾才执行
multi_line_mode = safe
# 关键字大小写:upper / lower / auto
keyword_casing = upper
# 是否启用语法高亮
highlight = True
# 补全时是否显示表名的 schema 前缀
qualify_columns = always
# 智能补全(基于元数据)
smart_completion = True
# 模糊匹配:usod 可匹配 user_orders
fuzzy_search = True
# 是否显示执行耗时(等价于 \timing on)
timing = True
# 表名后缀过滤,排查线上库时很有用
# table_format = psql
# 结果行数上限(防止误查大表把终端刷爆)
row_limit = 1000
# 历史文件
history_file = ~/.config/pgcli/historyini
# 亦可直接指定「启动时自动执行的命令」,等价 psql 的 ~/.psqlrc
# ~/.config/pgcli/config 中的 [main] 段落不支持 SQL,故用别名方式实现:bash
# 在 ~/.bashrc / ~/.zshrc 中定义别名,实现「带默认上下文启动」
alias pgl='pgcli -h 127.0.0.1 -p 5432 -U app_user -d demo'
alias pgl-prod='pgcli -h 10.0.0.10 -U read_only -d demo_prod'
# 让 pgcli 读取 psql 风格的 rc 文件(部分版本支持 --rcfile)
pgcli --rcfile ~/.psqlrc -d demo详细说明
pgcli 与 psql 的能力对照
| 能力 | psql | pgcli |
|---|---|---|
| 语法高亮 | 无 | 有(实时着色) |
| 智能补全(表/列/函数) | 有限(\d 前后 Tab) | 有(元数据驱动) |
| 模糊匹配补全 | 无 | 有 |
| 多行编辑 | 有(编辑缓冲区) | 有(更接近现代编辑器) |
\d / \dt / \l 等元命令 | 原生 | 兼容实现(绝大多数可用) |
\copy | 原生 | 支持 |
\e 外部编辑器 | 支持 | 支持(EDITOR 环境变量) |
\watch | 支持 | 兼容(版本依赖) |
\gexec | 支持 | 支持 |
\set 变量 | 原生 | 部分兼容 |
-c / -f 非交互模式 | 原生 | 支持 |
输出格式(\pset) | 最全(csv/html/latex 等) | 常用格式 |
| 环境依赖 | 仅 libpq | 需要 Python 运行时 |
| 启动速度 | 极快(毫秒级) | 较慢(数百毫秒) |
| 脚本可靠性 | 最高 | 建议改用 psql |
结论:交互式探索用 pgcli,生产脚本用 psql。二者可共存,别名互不冲突。
补全与高亮细节
pgcli 的补全是上下文感知的:
- 位置感知:在
SELECT后补全列名与函数;在FROM后补全表名与视图;在JOIN后优先补全可连接的表 - 元数据驱动:补全列表来自数据库系统目录(System Catalog),新加的表无需重启即可出现
- 模糊匹配:
usod→user_order_detail,coem→customer_email - 多候选切换:
Tab触发补全,Shift + Tab反向切换候选,Esc关闭候选列表 - 别名感知:
SELECT u.后只补全u别名对应表的列
sql
-- 补全示例:输入 `sele` + Tab 自动补全为 SELECT
-- 输入 `SELECT * FROM usod` + Tab,候选出现 user_order_detail
sele * frm user_order_detail wt uod
jion user_orders uo on uo.id = uod.order_id
wt uod.created_at > now() - intervl '7 days';text
# 补全候选列表示意(按 Tab 后)
> SELECT * FROM user_ord| ← 光标位置
user_orders
user_order_detail
user_order_statspgcli 的高亮规则:
| 元素 | 默认颜色 | 说明 |
|---|---|---|
| SQL 关键字 | 青色/加粗 | SELECT、FROM、WHERE 等 |
| 字符串字面量 | 绿色 | '2026-01-01' |
| 数字 | 黄色 | 100、3.14 |
| 内置函数 | 品红 | now()、count() |
| 表名/列名 | 白色 | 普通标识符 |
| 错误提示 | 红色 | 语法或执行错误 |
多行模式与执行控制
pgcli 提供三档多行模式:
| 模式 | 行为 | 建议 |
|---|---|---|
off | 回车即执行(同 psql 单行) | 习惯 psql 者 |
safe | 仅当语句以 ; 结尾才执行,否则换行 | 推荐默认 |
always | 回车始终换行,用 Esc + Enter 执行 | 编写长 SQL |
text
# safe 模式下的交互示意(> 提示符)
demo> SELECT id, email
demo> FROM users
demo> WHERE status = 'active' ← 尚未输入分号,继续换行
demo> ;
id | email
----+---------------------
1 | alice@example.com
(1 row)text
# always 模式下用 Esc 再回车执行
demo> SELECT count(*) FROM orders
demo> WHERE created_at >= now() - interval '1 day'
demo> [Esc][Enter] ← 触发执行
count
-------
1842
(1 row)常用操作与快捷键
| 快捷键 | 功能 |
|---|---|
Tab | 触发补全 / 切换到下一个候选 |
Shift + Tab | 切换到上一个候选 |
Esc 然后 Enter | 在 always 模式下执行 |
Ctrl + R | 反向搜索历史 |
Ctrl + C | 中止当前输入或查询 |
Ctrl + D | 退出 pgcli |
F2 | 切换多行模式 |
F3 | 切换补全开关 |
F4 | 切换语法高亮 |
Ctrl + Space | 强制显示补全候选 |
pgcli 也实现了大量 psql 元命令:
sql
-- 服务端信息
\conninfo -- 当前连接详情(含 SSL 状态)
\l -- 列出数据库
\dt -- 列出表
\dt+ -- 列出表(含大小与描述)
\d users -- 查看表结构
\dn -- 列出 schema
\du -- 列出角色
\df -- 列出函数
\dx -- 列出扩展
\dp users -- 查看表权限sql
-- 输出与执行控制
\timing on -- 显示执行耗时
\x auto -- 宽结果自动转纵向显示
\o /tmp/result.txt -- 后续结果写入文件
\i ./migrations/001_init.sql -- 执行外部 SQL 文件
\e -- 用 $EDITOR 打开编辑器编写 SQL
\pset pager off -- 关闭分页器,便于复制结果
\q -- 退出实战示例
场景一:用补全快速写一条多表查询
目标:查询近 7 天各渠道的订单金额与退款率。
sql
-- 第 1 步:先用 \dt 确认表名(Tab 补全可省去手输)
\dt
-- 第 2 步:利用别名补全编写查询
SELECT o.channel,
count(*) AS order_cnt,
sum(o.amount) AS gmv,
count(*) FILTER (WHERE o.status = 'refunded') AS refund_cnt,
round(
100.0 * count(*) FILTER (WHERE o.status = 'refunded') / count(*),
2
) AS refund_rate
FROM orders AS o
WHERE o.created_at >= now() - interval '7 days'
GROUP BY o.channel
ORDER BY gmv DESC;text
# 输出示例(pgcli 会按列宽自动对齐)
channel | order_cnt | gmv | refund_cnt | refund_rate
----------+-----------+----------+------------+-------------
app | 8123 | 4213380 | 94 | 1.16
web | 4102 | 2188660 | 61 | 1.49
miniapp | 2308 | 962450 | 38 | 1.65
offline | 412 | 386200 | 7 | 1.70
(4 rows)
Time: 0.187s场景二:用 pgcli 做一次带 SSL 校验的连通性检查
bash
# 在 CI 或跳板机上,用 pgcli 快速确认「能连、且走的是 SSL」
pgcli "postgresql://app_user:secret@db.example.com:5432/demo?sslmode=verify-full&sslrootcert=/etc/pki/ca.crt" \
-c "\conninfo"text
# \conninfo 输出示例
You are connected to database "demo" as user "app_user" on host "db.example.com" (address "10.0.0.21") at port "5432".
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)场景三:把 pgcli 用于日常巡检的包装脚本
bash
#!/usr/bin/env bash
# inspect-pgcli.sh:交互巡检入口,避免每次都手输连接参数
set -euo pipefail
DB_URL="${DATABASE_URL:?请先设置 DATABASE_URL}"
exec pgcli "${DB_URL}" \
--row-limit 500 \
--timingbash
# 使用方式
export DATABASE_URL="postgresql://app_user:secret@127.0.0.1:5432/demo"
chmod +x inspect-pgcli.sh
./inspect-pgcli.sh
# 进入后常用三连
# \conninfo 确认连接与 SSL
# \dt+ 看表大小,找出异常膨胀的表
# \timing on 开启计时后跑排查查询注意事项
- 不要用 pgcli 跑生产批处理:pgcli 的启动开销与补全元数据查询会拖慢脚本;且其元命令实现是「兼容层」而非原生,边界行为可能与 psql 有差异。批处理请用
psql -f。 - 补全会连库查元数据:首次补全可能触发系统目录查询,在表特别多(上万张)的库上会有可感知延迟。可用
fuzzy_search = False或关闭补全(F3)缓解。 row_limit是保护伞:默认限制返回行数,避免误查大表刷爆终端。做精确统计时注意别被截断——需要全量结果时应改用\o或psql -c。- Python 环境隔离:用
pip install pgcli而非 pipx 时,容易与系统 Python 包冲突(尤其是psycopg版本),优先用 pipx。 - 版本对齐:pgcli 依赖的
psycopg需支持 PostgreSQL 18 的协议与认证(如scram-sha-256为默认时的握手)。连接报认证错误时先升级 pgcli 与驱动。 - 密码安全:不要在命令行直接写
-W之外的口令,也不要把带密码的 DSN 写进 shell 历史。使用~/.pgpass(权限600)或PGPASSWORD环境变量。
bash
# 正确:使用 .pgpass,避免密码进入 shell 历史
# ~/.pgpass 内容格式:hostname:port:database:username:password
echo "127.0.0.1:5432:demo:app_user:secret" >> ~/.pgpass
chmod 600 ~/.pgpass
# 之后连接不再需要输入密码
pgcli -h 127.0.0.1 -U app_user -d demo- 历史文件可能含敏感 SQL:pgcli 的历史记录默认落盘,若查询中含个人信息或密钥,应定期清理或关闭历史(
history_file指向临时目录)。
最佳实践
- psql 与 pgcli 双持:日常交互用 pgcli,脚本与排障用 psql。两者共享
~/.pgpass、~/.pg_service.conf、环境变量,无需重复配置。 - 把连接固化到 service 文件:用
~/.pg_service.conf+pgcli service=xxx,避免在命令历史里散落主机名与账号。 - 开
timing与\x auto:前者让性能问题一眼可见,后者让宽表结果更可读。 - 用
F3/F4动态开关:在大库上感到卡顿时临时关补全,需要时再开,比改配置重启更快。 - 把常用巡检 SQL 存成文件:用
\i载入,比每次手敲更可靠,也便于纳入 Git。 - 不迷信美化:高亮与补全提升的是输入效率,不改变 SQL 语义。执行计划、索引、锁的分析仍需回到
EXPLAIN与服务端视图。
下一节
继续学习:postgres 用户与密码设置