1

我正在调试一个 bash 脚本,并将我的问题归结为这个非常简单的脚本。它在 CentOS 5.7 中运行:

# tmp.sh
function do_as_someuser {
  sudo -u someuser -i "$1"
}

do_as_someuser "ls -l"       # line 1
#do_as_someuser "A=1 ls -l"  # line 2

someuser当我执行此脚本仅取消注释第 1 行时,它会按预期显示 的主目录的列表:

[root@centos57 test]# ./tmp.sh 
total 4
drwxr-xr-x 4 someuser someuser 4096 Mar 14 23:36 some_dir
[root@centos57 test]# 

但是当我只取消注释第 2 行时,它会将我记录为someuser并且不会返回到我的用户提示,这绝对不是我所期望的。毕竟,为什么定义一个变量会有所作为呢?

[root@centos57 test]# ./tmp.sh 
[someuser@centos57 ~]$ 

A=1 ls -l当我直接在命令行中编写它时,它运行得非常好。如果这是一个有效的命令,我当然应该能够执行它,将它作为参数传递给sudo,不是吗?

我的问题:

  • 为什么会这样?
  • 如何修改do_as_someuser以便它执行具有变量分配的命令?
4

2 回答 2

2

认为正在发生的事情是它sudo本身将“var = value”形式解释为环境变量赋值,而不是仅仅将它传递给shell。就sudo目前而言,您正在分配A具有价值1 ls -l,然后不运行命令。例如,这是一个快速控制台会话:

$ sudo -i "X=5 ls"
root# echo $X
5 ls

根据快速测试,您可以通过在--要运行的命令之前使用该选项来避免该问题:

$ sudo -i -- "X=5 ls"
... files ...
$ sudo -i -- 'BLORT=zorch env' | grep BLORT
BLORT=zorch
SUDO_COMMAND=/bin/sh -c BLORT=zorch env
于 2013-03-14T23:11:20.180 回答
2

实现您想要的一种方法是使用

sudo -u someuser $SHELL -c "A=1; ls -l; echo \$A"

即,在您以该用户身份执行的shell 命令的开头将要穿梭的变量赋值到其他用户上下文中。

一个更具可读性的替代方案证明了这一点:

sudo -u someuser $SHELL -c "FOOBAR=BAZ env|grep FOOBAR"

为什么会这样?我认为这是因为sudo没有使用 shell 作为中介来执行你给定的命令。然而,这就是我上面给出的命令的作用。从错误消息中,-i我假设bash(或者在任何情况下来自 的登录 shell passwd)正在尝试exec(3)执行命令而不是拆分参数 - 坦率地说,它怎么知道如何正确拆分它?:

$ sudo -u someuser $SHELL -i "FOOBAR=1 env|grep FOOBAR"
bash: FOOBAR=1 env|grep FOOBAR: No such file or directory

但我相信手册页sudo在这种情况下的实现是错误的(-i选项文档):

如果指定了命令,则通过 shell 的-c选项将其传递给 shell 以执行。

如您所见,由于使用了必须转义的变量,因此上述内容并不十分方便。

继续你的例子:

# tmp.sh
function do_as_someuser {
    sudo -u someuser $SHELL -c "$1"
}

do_as_someuser "ls -l"       # line 1
do_as_someuser "A=1 ls -l"   # line 2

-i我从您的问题中不明白的部分是为什么您在期望命令运行并返回时坚持使用...为什么是初始登录外壳呢?你需要来自.profileet 的东西吗?人。?

于 2013-03-14T23:38:59.803 回答