概述
我尝试以不同的用户身份执行命令而不使用引号,同时确保执行的命令不会从父 shell 继承环境。
runuser看起来是这项工作的完美候选人,因为它将由特权用户执行(在无人值守的脚本中),没有位,具有登录/ PAM 会话支持,并且它是广泛使用的软件包setuid
的一部分。util-linux
问题
编辑:进一步澄清:
这里的罪魁祸首是我想在同一个脚本中的多个用户之间切换,并从执行命令的用户的角度执行命令。目前,像
$USER
或这样的变量甚至~/
会扩展为来自父 shell 的值,这会破坏整个设置。很长一段时间以来,我一直在使用 Bash,-c
但这需要引号,这使得带有正则表达式的命令难以阅读。
原始问题:
目标是显示用户主目录的目录监听(含义
~/
应翻译为/home/build
)作为build
用户(其中“受污染”的 shell 将返回/root
)。不应使用引号(以避免必须使用更高级的命令来转义引号)。
以下方法几乎可行,但不幸的是它从父会话继承了环境:
$ whoami
root
$ runuser --user build -- ls -a ~/
ls: cannot open directory '/root/': Permission denied
我尝试过的另一种替代方法是创建一个登录会话,但由于 Bash 的性质,参数不会被解析为command_string,而是被解析为脚本:
$ runuser --login build -- ls -a ~/
/usr/bin/ls: /usr/bin/ls: cannot execute binary file
从逻辑上讲,这通常可以通过-c
向 Bash 提供参数来解决,但这又让我们回到原点,它需要引号:
$ runuser --login build -- -c 'set -x; ls -a ~/'
+ ls -a /home/build/
调用单独的脚本可以满足所有要求,但是我发现这种方法使用起来很麻烦:
# run.sh
whoami
ls -a ~/
$ chown build run.sh
$ chmod +x run.sh
$ runuser build ./test.sh
+ whoami
build
+ ls -a /home/build/
问题
还有其他方法可以让您在干净的环境中以不同用户身份执行命令时避免使用引号吗?
更新 1
Heredoc 是最接近满足所有标准的解决方案,但如果还有更多,我很乐意听到!
# run.sh
runuser --user build -- bash << EOF
set -x
ls -l ~/
whoami
EOF
# Result
+ ls -l /home/build/
total 4
-rwxrwxrwx 1 1000 1000 771 Jul 6 20:12 run.sh
+ whoami
build
更新 2
将函数导出到子 shell 也是可行的,并且保留语法高亮
function CMD {
set -x
echo $USER
ls -l ~/
}
runuser --login build -- -c "$(declare -f CMD); CMD"
我会用:
这
-l
使得它继承了作为该用户(用户环境)的正常内容,因此$USER
应按~
预期进行解释。您可能会遇到类似的丑陋的命令
-c 'cmds here'
,但您可以创建一个接受用户的脚本; cmd,然后您的 cmd 看起来就不会那么丑陋了。我相信我也遇到过同样的问题,我只是向
/usr/bin
或/usr/local/bin
名为 runwithenv 添加了一个小脚本并将其设置为可执行。然后sudo
或以 root 身份运行runwithenv
带有参数 user;cmds-to-be-run 的脚本。或者,因为你将有 2 个脚本,所以只需编写一个名为的函数
runwithenv
:然后只需使用不同的用户重复调用该函数:
可能需要向函数添加陷阱或测试并回显结果,以便您可以对其进行编程。
这满足所有要求:
runuser
。setuid
在隔离环境中无需位即可完成的(意味着不从父 shell 继承变量)。~/
或$USER
已正确设置为调用用户。set -x
设置正确(++
)。shellcheck
。-c
格式的可能性。解决方案是通过可选参数
-c
和一些巧妙的技巧来实现的(参见代码中的注释):代码:
修订:https://gist.github.com/GrabbenD/01803465f4c2413bf7103caa15dc6791
希望这可以节省一些人几个小时的研究时间:)