Bash脚本调用sudo执行命令提示Permission denied权限报错排查
问题根因
一共三个核心问题导致报错:
- 第31行的权限错误是经典的sudo重定向失效问题:你写的
sudo cat <<- EOF > /etc/apache2/sites-available/"$1".com.conf里,sudo只给cat命令提了root权限,但是后面的>写入重定向动作是当前执行脚本的普通用户shell提前处理的,普通用户本身没有/etc/apache2/sites-available/目录的写入权限,哪怕cat跑在root身份下,写入目标文件的动作还是普通用户执行,直接触发Permission denied。 - sudoers配置规则写错:你配置的
/home/eric/bin/是目录路径,sudo规则中仅填写目录路径(必须以/结尾才会被识别为目录规则)时,只会匹配该目录下的一级直接可执行文件,不会递归匹配,而且你当前的规则仅对执行/home/eric/bin/下的命令免密,脚本内部调用的cat、a2ensite、a2dissite、systemctl等命令都不在你配置的免密路径范围内,这些命令提权时不会触发免密规则。 - 第43行的报错是shell语法错误:
if [ sudo a2ensite "$1".com.conf ]写法完全错误,[是系统自带的test命令,不能直接把sudo命令放在方括号内作为判断条件,语法解析直接报错。另外你else分支用单引号包裹的提示字符串不会解析$1变量,输出时会直接显示$1而不是传入的站点名。
修复方案
按以下步骤修改即可解决:
- 修复虚拟主机配置文件写入逻辑,替换掉失效的sudo重定向写法,用提权的tee命令完成写入,避免普通用户无权限写系统目录的问题:
sudo tee /etc/apache2/sites-available/"$1".com.conf > /dev/null <<- EOF <VirtualHost *:8080> ServerAdmin eric@sabresong.com ServerName sabresong.local ServerAlias "$1" DocumentRoot /var/www/"$1"/public_html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> EOF
末尾加> /dev/null是为了屏蔽tee默认把写入内容打印到终端的行为。
2. 修复if判断的语法错误,去掉多余的方括号,shell中if直接接命令即可根据命令返回值判断执行结果(返回0走then分支,非0走else分支),同时修正单引号导致变量不解析的问题:
if sudo a2ensite "$1".com.conf; then echo "$1 enabled" sudo a2dissite 000-default.conf echo "Restarting Apache" sudo systemctl restart apache2 echo "Finished!" else echo "WARNING! Could not enable new site $1" fi
- 修正sudoers配置,学习测试环境图省事的话推荐直接用sudo执行整个脚本,逻辑更简单:
- 删掉脚本内部所有的
sudo前缀,因为脚本开头创建/var/www下目录、修改文件属主的操作本身也需要root权限,普通用户默认没有/var/www目录写入权,整脚本提权跑就不需要内部反复写sudo。 - 用visudo修改sudoers规则,删掉之前写的目录规则,换成脚本的完整绝对路径:
eric ALL=(ALL:ALL) NOPASSWD: /home/eric/bin/makevhost,之后直接执行sudo makevhost 你的站点名就可以全程免密跑通。
- 删掉脚本内部所有的
注意:sudoers中配置目录路径的写法本身安全风险较高,因为只要用户对该目录有写入权限,就可以替换任意二进制文件获取root权限,仅适合完全个人可控的测试环境使用,生产环境禁止这么配置。
内容的提问来源于stack exchange,提问作者Sabresong
相关产品推荐
相关产品推荐

