使用 PostgreSQL 官方 psql 客户端的命令行工作流。适用于需要连接 PostgreSQL 数据库、检查 schema、表、索引、角色或权限、执行临时 SQL 或 .sql 脚本、用 COPY 或 \copy 导入导出数据、排查连接或权限失败,或把数据库管理诉求翻译成安全的 psql 命令的场景。
把 psql 当作 PostgreSQL 官方命令行客户端来使用。凡是任务以 shell 为主、需要依赖 PostgreSQL 元命令做结构检查,或需要把数据库管理诉求落成可执行的 psql 命令时,优先使用本 skill。
host、port、dbname、username、SSL 模式,以及认证方式。\conninfo
SELECT current_user, current_database(), current_schema();
SHOW search_path;
psql 元命令做发现,再决定是否需要手写 catalog SQL。按环境选择合适的形式:
psql -h <host> -p <port> -U <user> -d <dbname>
psql "postgresql://<user>@<host>:<port>/<dbname>?sslmode=require"
PGPASSWORD='<password>' psql -h <host> -U <user> -d <dbname>
优先使用 .pgpass、环境变量或交互式密码提示,不要把密码写进可复用脚本,更不要写进源码。
日常检查优先用元命令:
\l
\dn
\dt
\dv
\df
\du
\d+ <table_name>
\dp <table_name>
如果任务是“库里有什么对象”或“为什么这个角色访问不了这张表”,先停留在发现模式,直到目标对象和权限路径都明确为止。
一次性 SQL:
psql -h <host> -U <user> -d <dbname> -c "SELECT now();"
psql -h <host> -U <user> -d <dbname> -At -c "SELECT count(*) FROM public.users;"
可重复脚本:
psql -h <host> -U <user> -d <dbname> -v ON_ERROR_STOP=1 -f migrations.sql
如果输出要给 shell 消费,优先加 -At。只要脚本稍微复杂,就加 -v ON_ERROR_STOP=1,确保失败直接暴露。
自动化场景优先使用稳定基线:
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> -f script.sql
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> -c "SELECT now();"
这些参数的作用:
-X:禁用 ~/.psqlrc,避免本地用户配置污染自动化行为。-v ON_ERROR_STOP=1:遇到第一处错误就停止,而不是继续往下跑。-P pager=off:避免 pager 导致卡住或输出不可控。-At:适合把结果直接交给 shell 继续处理。命令选择规则:
-c。-f 或 \i。在追求稳定和速度时,优先从这些模板起步:
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> -c '\conninfo'
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> \
-c '\conninfo' \
-c 'SELECT current_user, current_database(), current_schema();'
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> <<'SQL'
\conninfo
\dn
\dt
SELECT now();
SQL
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> -f script.sql
docker exec <container_name> bash -lc "PGPASSWORD='<password>' psql -X -v ON_ERROR_STOP=1 -P pager=off -U <user> -d <dbname> -c '\\conninfo'"
docker exec <container_name> bash -lc "PGPASSWORD='<password>' psql -X -v ON_ERROR_STOP=1 -P pager=off -U <user> -d <dbname> -f /workspace/bootstrap.sql"
docker exec -i <container_name> bash -lc "PGPASSWORD='<password>' psql -X -v ON_ERROR_STOP=1 -P pager=off -U <user> -d <dbname>" <<'SQL'
\conninfo
\copy public.customers TO '/workspace/customers_export.csv' CSV HEADER
SELECT count(*) FROM public.customers;
SQL
记住:\copy、\d、\conninfo 这类命令是 psql 元命令,不是 SQL。它们由 psql 自己解析,所以转义和执行上下文都很重要。
稳妥写法:
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> \
-c '\conninfo' \
-c 'SELECT current_user, current_database(), current_schema();'
多个 -c 会按顺序在同一个 psql 会话内执行,这通常是 agent 最稳的短命令形式。
psql -X -v ON_ERROR_STOP=1 -P pager=off -h <host> -U <user> -d <dbname> <<'SQL'
\pset pager off
\conninfo
SELECT current_user, current_database(), current_schema();
SQL
\conninfo
SELECT current_user, current_database(), current_schema();
\copy public.users TO './users.csv' CSV HEADER
如果 heredoc 或 shell 字符串里出现 invalid command \\,优先怀疑转义层数错了。
区分服务端 COPY 和客户端 \copy:
COPY:数据库服务端必须能访问那个文件路径。\copy:文件路径属于运行 psql 的客户端进程。常见写法:
\copy public.users to './users.csv' csv header
\copy public.users from './users.csv' csv header
COPY public.users TO '/server/path/users.csv' CSV HEADER;
如果环境是远端或托管数据库,优先用 \copy,避免假设数据库主机能直接读你的文件。
当 \copy 出现在脚本、heredoc 或 shell 命令里时,记住它仍然是 psql 元命令,不要把它当普通 SQL 包装。
在容器环境里,\copy 读写的是运行 psql 的那个文件系统。如果 psql 是通过 docker exec 进去跑的,通常用的是容器路径,不是宿主机路径。
如果导入要求“保留已有数据”,优先使用显式 staging 模式:
BEGIN;
CREATE TEMP TABLE customers_import (
email TEXT,
full_name TEXT,
tier TEXT
) ON COMMIT DROP;
\copy customers_import FROM './import_customers.csv' CSV HEADER
INSERT INTO public.customers (email, full_name, tier)
SELECT email, full_name, tier
FROM customers_import
ON CONFLICT (email) DO NOTHING;
COMMIT;
这种模式把导入过程和去重语义写得很清楚。
连接失败时按这个顺序检查:
pg_hba.conf 或角色权限查询失败时按这个顺序检查:
search_path\d、\dt、\dn 确认对象是否存在\dp 或 catalog 查询确认权限COPY 还是 \copy权限失败时,优先跑这组固定检查:
\conninfo
SELECT current_user, current_database(), current_schema();
\dp schema_name.table_name
\du
SELECT has_schema_privilege(current_user, 'schema_name', 'USAGE');
SELECT
has_table_privilege(current_user, 'schema_name.table_name', 'SELECT') AS can_select,
has_table_privilege(current_user, 'schema_name.table_name', 'INSERT') AS can_insert,
has_table_privilege(current_user, 'schema_name.table_name', 'UPDATE') AS can_update,
has_table_privilege(current_user, 'schema_name.table_name', 'DELETE') AS can_delete;
这能快速区分:连错对象、连错角色、schema 不对、缺 schema usage、缺表级授权。
DELETE 或 UPDATE 尽量放事务里。