这正如我所期望的那样工作:
$ sudo -u romain bash -c 'a="b" ; echo $a'
b
$
但是跟-i
变量没有回显,为什么呢?
$ sudo -iu romain bash -c 'a="b" ; echo $a'
$
我想知道是否-i
添加了一定程度的 bash 间接或变量插值,但如果是,这如何工作?
$ sudo -iu romain bash -c 'a="b" ; echo ${a}'
b
$
答案1
当您使用-i
with时sudo
,将使用用户的登录 shell ,$SHELL
并将作为登录 shell 进行调用。
当您另外向该命令提供要运行的命令时,如
sudo -u user -i 'some-command'
...sudo
将使用 运行该命令$SHELL -c
,这意味着它需要将其获取的参数列表转换为单个命令行字符串,该字符串再次由 shell 求值。为此,它必须转义 中的每个字符(some-command
字母数字、下划线、连字符和美元符号除外)。
这意味着
sudo -u user -i bash -c 'a="b" ; echo ${a}'
将以用户身份执行user
,转义为相当于
$SHELL -c bash\ -c\ \'a\=\"b\"\ \;\ echo\ $\{a\}\'
...使用时$a
将命令变成
$SHELL -c bash\ -c\ \'a\=\"b\"\ \;\ echo\ $a\'
请注意,在最后一个命令中,$a
在启动之前由用户的登录 shell 展开bash -c
。在前面的命令中,${a}
使用了 where ,$\{a\}
不是有效的扩展,因此用户的 shell 不会进行扩展,而内联bash -c
shell 会看到${a}
并可以扩展它。
sudo
手册中描述选项的部分对此进行了解释-i
:
-i, --login
Run the shell specified by the target user's password
database entry as a login shell. This means that login-
specific resource files such as .profile, .bash_profile, or
.login will be read by the shell. If a command is specified,
it is passed to the shell as a simple command using the -c
option. The command and any arguments are concatenated,
separated by spaces, after escaping each character (including
white space) with a backslash (‘\’) except for alphanumerics,
underscores, hyphens, and dollar signs. If no command is
specified, an interactive shell is executed. [...]
答案2
这是由于 sudo 如何转义它在命令行上获得的参数以将其提供给另一个 shell(sudo -i
运行目标用户的登录 shell,而 plainsudo
则不运行)之间存在奇怪的交互。
特别是,它留下了美元符号$
不是引用,这样的命令就像
sudo -i /bin/echo '$USER'
工作。
如果它做过也引用美元符号,那是行不通的,但是
sudo -i sh -c 'echo "$USER"'
应该。好吧,我的意思是我认为它应该有效,但是那个运行二shell(目标用户的登录 shell,以及sh
我们特别要求的)并考虑通过它进行转义是一件痛苦的事情。
该$USER
示例似乎不太有用,但您可能希望使用其他一些变量来运行它,以检查用户在登录环境中获得的值。
不管怎样,这就是这个 sudo bug 报告中使用的示例命令,它导致了我认为仍然是当前的行为:
- Bug 564 - sudo 正在转义 $,无法访问环境变量(bugzilla.sudo.ws)
sudo -i sh -c 'echo $foo'
这里讨论了这种被破坏的特殊情况:
(后一个是链接到评论中到一个关于同一问题的较早问题)