SSH脚本执行make调用yapf/pylint报Permission denied错误
问题环境
- 服务器操作系统为Debian 11,登录账号为
user,该账号属于sudo用户组 - 项目部署目录为
/app,目录下Makefile配置了代码格式化、代码检查相关目标,具体定义如下:
make format: yapf -ir -vv --style pep8 . make lint: cd ..; pylint app --verbose --disable=R,C -sy
故障现象
- 手动通过SSH以
user账号登录服务器,进入/app目录执行make format命令可正常运行;若执行sudo make format则返回如下错误,退出码127:
yapf -ir -vv --style pep8 . make: yapf: No such file or directory make: *** [makefile:5: format] Error 127
- 本地通过带heredoc的SSH脚本远程连接服务器自动执行部署流程,运行到
make format、make lint步骤时,分别返回权限拒绝错误,退出码127:
yapf -ir -vv --style pep8 . make: yapf: Permission denied make: *** [makefile:5: format] Error 127
/bin/sh: 1: pylint: Permission denied make: *** [makefile:7: lint] Error 127
所用SSH远程执行脚本完整内容如下:
ssh -p 4444 -i /mykey user@ip << 'ENDSSH' echo 'deploying zabbix' cd /zabbix && docker-compose up -d echo 'zabbix deployed' echo 'copying zabbix module to container' sudo mkdir -p /var/lib/zabbix/modules/dockermodule docker cp /zabbix/zabbix_module_docker.so zabbixserver:/var/lib/zabbix/modules/dockermodule echo 'copied zabbix module to container done' echo 'extracting tar file' sudo rm -rf /app/* && sudo tar -xf /tmp/project.tar -C / sudo chown -R user /app sudo chmod -R u=rwx /app echo 'tar file extracted' echo 'going into app folder' cd /app echo 'getting rid of hidden macos files' sudo find . -type f -name '._*' -delete echo 'hidden macos files deleted' echo 'running install' make install echo 'install done' echo 'running format' make format echo 'format done' echo 'running lint' make lint echo 'lint done' echo 'running test' make test echo 'test done' #echo 'running vulnerability check' #trivy fs --security-checks vuln --severity HIGH,CRITICAL / > security_check.txt #echo 'vuln check done' echo 'running docker build & run' make docker echo 'docker built and running' ENDSSH
已尝试排查操作
- 已通过chown将
/app目录所有者修改为user,并通过chmod给目录配置用户、用户组、其他用户的读写执行权限,问题仍未解决 - 若在SSH脚本中不通过make调用,直接写入yapf、pylint对应的原生命令,命令可正常执行无报错
根因定位
两类报错核心原因都是不同执行上下文的PATH环境变量不一致,和/app目录权限无关:
- sudo执行报找不到命令:Debian默认sudo配置会通过
secure_path重置PATH变量,仅保留系统级二进制目录(/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)。如果yapf、pylint是通过pip用户级安装,存放在/home/user/.local/bin这类用户私有路径下,sudo执行时PATH不含该路径,自然无法定位到可执行文件,触发127退出码。 - 非交互式SSH脚本执行报权限拒绝:SSH通过heredoc传递命令执行时,属于非交互式非登录shell,不会加载
.bashrc、.profile等用户shell配置文件,PATH变量取值和手动交互式登录时不一致。此时make启动的/bin/sh子shell继承的是受限PATH,要么定位到无执行权限的同名文件,要么指向当前上下文无访问权限的路径,触发权限拒绝错误。
直接在脚本中写原生命令能正常执行,是因为当前shell的命令hash缓存、路径解析逻辑能命中正确的可执行文件位置,但make拉起的独立子shell不会继承这层解析结果。
解决方案
任选以下一种方案即可修复,优先选第一种,无环境依赖:
- 方案1:Makefile中使用命令绝对路径
手动登录服务器执行which yapf、which pylint拿到两个命令的完整绝对路径,替换Makefile中的裸命令名即可,不受PATH变量变化影响,示例:
format: /home/user/.local/bin/yapf -ir -vv --style pep8 . lint: cd ..; /home/user/.local/bin/pylint app --verbose --disable=R,C -sy
- 方案2:执行前主动补全PATH配置
在SSH脚本调用make的步骤前,显式将yapf、pylint所在路径加入PATH;sudo调用make时加-E参数保留当前用户环境变量,示例:
如果需要长期使用sudo调用相关命令,可以修改# 调用make前加这行,路径替换为实际yapf/pylint所在目录 export PATH=$PATH:/home/user/.local/bin make format make lint # 如需sudo执行,用-E参数保留环境 sudo -E make format/etc/sudoers文件,在secure_path配置项末尾追加yapf/pylint所在目录路径。 - 方案3:全局安装依赖
用root权限执行pip3 install yapf pylint,将两个工具安装到/usr/local/bin这类系统默认PATH包含的全局路径下,所有执行上下文都能直接找到命令。
内容的提问来源于stack exchange,提问作者user19413311
相关产品推荐
相关产品推荐

