使用Python subprocess执行psql命令时出现“No such file or directory: psql”错误
问题
我在本地PostgreSQL实例上用以下命令可以正常列出所有数据库:
psql --host localhost --port 55000 --username postgres -At --command 'SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn ORDER BY datname;' postgres
但用Python subprocess执行时却报错:
FileNotFoundError: [Errno 2] No such file or directory: 'psql'
我的Python代码如下:
import subprocess import shlex source_host = "localhost" source_port = "55000" source_user = "postgres" source_password = "postgrespw" database_select_query = "SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn ORDER BY datname;" database_select_command = f""" psql \ --host {source_host} \ --port {source_port} \ --username {source_user} \ -At --command '{database_select_query}' \ postgres """ print(database_select_command) print(shlex.split(database_select_command)) output = subprocess.run( shlex.split(database_select_command), capture_output=True, shell=False, env={"PGPASSWORD": source_password}, ) print(output)
我试过转义引号、改成单行命令,问题还是没解决,到底忽略了什么?
解决方案
核心原因
subprocess执行命令时的环境变量PATH和你终端里的不一样——终端能找到psql是因为shell的PATH包含了PostgreSQL的bin目录,但Python脚本的执行环境没加载这个路径,导致系统找不到psql可执行文件。
具体解决办法
使用psql的绝对路径
先找到psql的完整安装路径(比如Linux下可能是/usr/bin/psql,macOS Homebrew安装的话是/usr/local/bin/psql,Windows下类似C:\Program Files\PostgreSQL\15\bin\psql.exe),把命令里的psql替换成绝对路径即可。
示例修改:database_select_command = f""" /usr/local/bin/psql \ --host {source_host} \ --port {source_port} \ --username {source_user} \ -At --command '{database_select_query}' \ postgres """给subprocess补充PATH环境变量
手动把PostgreSQL的bin目录添加到subprocess的环境变量中,保证系统能找到psql:import os # 获取系统原有PATH current_path = os.environ.get("PATH", "") # 替换成你实际的PostgreSQL bin目录 pg_bin_path = "/usr/local/bin" new_path = f"{pg_bin_path}:{current_path}" output = subprocess.run( shlex.split(database_select_command), capture_output=True, shell=False, env={"PGPASSWORD": source_password, "PATH": new_path}, )直接构造参数列表(推荐)
放弃用字符串拼接命令再拆分的方式,直接构造参数列表传递给subprocess,既能避免引号转义问题,也能绕开shlex解析的潜在问题:cmd_args = [ "psql", # 同样可以替换成绝对路径 "--host", source_host, "--port", source_port, "--username", source_user, "-At", "--command", database_select_query, "postgres" ] output = subprocess.run( cmd_args, capture_output=True, shell=False, env={"PGPASSWORD": source_password, "PATH": new_path}, )
内容的提问来源于stack exchange,提问作者Tim Estes
相关产品推荐
相关产品推荐

