是否有一个命令可以在特定目录中运行任意命令?
在 Debian 10 中,我可以简单地使用env --chdir
。但是,env --chdir
在我安装的 Debian 9 上不可用。
我想要运行的命令的一部分由 shell 变量组成,这些变量可能包含空格或其他特殊字符。例如,假设我想要运行的命令是:
strace -- "$@"
因此,以下内容将不起作用:
sudo -i sh -c 'cd my-directory && exec strace -- "$@"'
呃,你为什么要这么做?
我想使用sudo -i
/sudo --login
来运行命令。但我想在特定目录中运行该命令,而不是root用户的主目录。虽然sudo
可以设置环境变量,但似乎没有更改目录的选项。
我使用它sudo -i
是因为:1)我希望我正在运行的程序(我的 Ansible playbook)具有HOME=/root
,这将避免程序在我的主目录中创建 root 拥有的文件。 2) 这听起来像是一系列 with sudo
without问题的例子-i
;一个全新的环境听起来是解决我的问题的最原则的方法。
答案1
我将忽略exec
,-i
因为尚不清楚您对这些问题的要求是什么。
然而到cd
和sudo
,然后
( cd «a directory»; sudo «a command» )
括号()
创建一个子shell,cd
是内置的,然后是命令sudo
什么的。所以进程数与 相同env
。sudo
还操纵环境变量,因此可能不需要env
和sudo
。
答案2
您可以轻松编写一个名为的单独脚本chdir
:
#!/bin/sh
dir=$1 &&
shift &&
cd -- "$dir" &&
exec "$@"
如果没有单独的脚本,它会更加晦涩难懂:
sh -c 'cd -- "$1" && shift && exec "$@"' sh my-directory "$@"
然而,这并没有实现问题中解释的真正目标。您可能认为可以使用上面的脚本并运行sudo --login chdir my-directory ...
。这可能在大多数情况下都有效,但我认为这是一个坏主意。看着man sudo
:
-i
,--login
运行由目标用户的密码数据库条目指定的 shell 作为登录 shell。这意味着 shell 将读取特定于登录名的资源文件,例如 .profile、.bash_profile 或 .login。如果指定了命令,则会通过 shell 的
-c
选项将其传递到 shell 执行。
sh -c
采用单个字符串参数。因此,它的工作效果如何,取决于与sudo
用户 shell 的引用约定的匹配程度。 Shell 引用非常可怕。
在实践中,当我尝试这个时,我发现某物奇怪的事情可能会发生。其他人的分析表明引用sudo
可能是“令人惊讶的”或“可怕的”。看:如果我从“sudo --login”运行“sh -c”,则它不会扩展位置参数。有没有解决的办法?
这是实现我真正目标的另一种方法。它不需要创建单独的脚本文件,但我们可以将它很好地包装为 shell 函数:
run_as_root() {
sudo --set-home \
bash -l \
-c 'exec "$@"' \
bash \
"$@"
}
解释:
sudo --set-home
- 以另一个用户身份运行命令。一些环境发生了改变,但另一些环境则被保留。强制HOME
设置为新用户主目录。bash -l
- 运行“登录 shell”,初始化环境。这假设您的root
用户尚未定制为使用与 不同的 shellbash
。bash -c 'inline shell script' arg0 arg1 arg2...
- 运行一个小的 shell 脚本。$0
被设置为arg0
、$1
被设置为arg1
等。注意$0
是特殊的。 shell 将$0
其视为自己的名称。当 shell 打印错误消息时,错误消息以 开头$0:
。因此,我们应该设置arg0
为bash
。exec
- 用另一个程序替换 shell 进程。"$@"
- 扩展到"$1" "$2" ...