使用sudo -u postgres执行psql提示命令未找到的问题分析
尝试以postgres用户身份运行psql时出现两种矛盾结果:
- 执行
sudo su - postgres进入会话后运行psql完全正常,该会话中postgres用户的~/.bashrc已配置正确的PATH - 直接执行
sudo -u postgres psql时,却提示sudo: psql: command not found
当前使用Fish Shell,自身用户会话的PATH配置正确,可直接执行psql;切换到Bash后执行sudo -u postgres psql则恢复正常,推测问题与Fish的PATH处理逻辑相关。相关测试输出如下:
➜ ~ psql psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "opc" does not exist ➜ ~ sudo -u postgres psql sudo: psql: command not found ➜ ~ echo $PATH /home/opc/.local /home/opc/.local/bin /usr/pgsql-15/bin /usr/pgsql-15/bin /usr/local/bin /usr/bin /usr/local/sbin /usr/sbin ➜ ~ sudo echo $PATH /home/opc/.local /home/opc/.local/bin /usr/pgsql-15/bin /usr/pgsql-15/bin /usr/local/bin /usr/bin /usr/local/sbin /usr/sbin ➜ ~ sudo -u postgres /usr/pgsql-15/bin/psql could not change directory to "/home/opc": Permission denied psql (15.1) Type "help" for help. postgres=#
原因解释
sudo echo $PATH的输出具有误导性
这里的$PATH是被当前Fish Shell提前解析的,并非sudo执行环境中的PATH。也就是说,sudo echo $PATH实际是当前用户的PATH被替换后,再传给sudo执行echo命令,所以显示的是你当前Fish会话的PATH,而非sudo切换到postgres用户时的真实PATH。Fish与Bash对sudo的PATH传递逻辑不同
Bash默认会在执行sudo时保留部分用户PATH(除非配置了secure_path),而Fish在处理sudo时,会严格遵循sudo的secure_path配置(通常在/etc/sudoers中定义),不会直接传递当前用户的PATH。另外,postgres用户的~/.bashrc只有在登录式shell(比如sudo su - postgres这种带-参数的方式,会加载登录shell配置)才会被加载,而sudo -u postgres psql属于非登录式shell,不会加载postgres的.bashrc,因此postgres用户的PATH中没有包含/usr/pgsql-15/bin。sudo的
secure_path限制
查看/etc/sudoers中的secure_path配置,大概率没有包含/usr/pgsql-15/bin。当sudo执行命令时,会优先使用secure_path定义的路径,而非用户当前的PATH,这就导致系统找不到psql命令。
解决办法
- 临时方案:直接使用psql的绝对路径执行:
sudo -u postgres /usr/pgsql-15/bin/psql - 永久方案1:修改
/etc/sudoers中的secure_path,添加/usr/pgsql-15/bin(必须用visudo命令编辑,避免语法错误导致sudo失效) - 永久方案2:在postgres用户的非登录shell配置中添加PATH,比如创建
~postgres/.profile(sudo执行非登录shell时会读取该文件),或者如果postgres用户也使用Fish,配置~postgres/.config/fish/config.fish添加set -gx PATH /usr/pgsql-15/bin $PATH
内容的提问来源于stack exchange,提问作者enrico_steez

