sudo结合bash进程替换失效问题排查及解决方案咨询
问题原因与解决方法
核心原因
你遇到的/dev/stdin: Permission denied错误,本质是bash的source /dev/stdin操作并非直接读取当前进程已打开的标准输入(fd 0),而是尝试打开/dev/stdin这个路径文件。尽管/dev/stdin是全局可读的符号链接,但解析它时需要访问/proc/self/fd/0,而sudo切换到nobody后,bash通过路径打开的方式触发了系统权限检查——这个管道由root进程创建,虽然nobody继承了fd 0,但路径打开的方式绕开了直接使用已打开的文件描述符,最终导致读取失败。
从输出的/proc/3243/fd/0权限可以看到,nobody确实拥有该文件描述符的读取权限,只是source的路径打开方式不适用这种场景。
解决方法
以下是三种可靠的解决方案:
方案1:让bash直接读取标准输入执行
不需要用source /dev/stdin,改用bash -s让bash从标准输入读取命令并执行,直接利用已继承的fd 0,避免路径打开的权限问题:
#! /bin/bash sudo -u nobody \ bash -s \ < <(echo "A=$(ls /root/.profile)")
如果需要验证变量,把验证逻辑也写入输入流:
#! /bin/bash sudo -u nobody \ bash -s \ < <(echo "A=$(ls /root/.profile)"; echo "echo 'A=$A'")
方案2:将内容嵌入bash命令字符串
把要执行的内容直接作为bash -c的命令参数,避免管道传递的权限问题:
#! /bin/bash content="A=$(ls /root/.profile)" sudo -u nobody bash -c "$content; echo 'A=$A'"
如果内容包含特殊字符(如引号、空格),用printf "%q"做转义处理:
#! /bin/bash content="A=$(ls /root/.profile)" sudo -u nobody bash -c "$(printf "%q" "$content"); echo 'A=$A'"
方案3:临时文件中转(适合长/复杂内容)
将内容写入临时文件,设置nobody可读权限后再source,这种方式最稳妥:
#! /bin/bash temp_file=$(mktemp) echo "A=$(ls /root/.profile)" > "$temp_file" chmod o+r "$temp_file" sudo -u nobody bash -c "source $temp_file; echo 'A=$A'" rm -f "$temp_file"
内容的提问来源于stack exchange,提问作者shrike
相关产品推荐
相关产品推荐

