使用 sudo 权限在当前 shell 中执行 shell 脚本

要在当前 shell 中执行 shell 脚本,需要使用句点 .source命令。但是,为什么它不工作的 sudo权限?

我有一个具有执行权限的脚本,名为 setup.sh:

$ sudo . ./setup.sh
sudo: .: command not found

source命令也会产生类似的错误。我错过了什么吗?要在 相同/电流 shell 中运行具有 sudo权限的脚本,我应该做什么?

195663 次浏览

基本上 sudo 期望,一个可执行文件(命令)遵循和您提供了一个 .

所以才会出错。

试试这样 $ sudo setup.sh


我认为你对采购和执行脚本之间的区别感到困惑。

执行脚本意味着创建一个新进程,并运行该程序。程序可以是 shell 脚本,也可以是任何其他类型的程序。因为它是一个子过程,程序中任何环境变量的改变都不会影响 shell。

源代码只能与 bash 脚本一起使用(如果您正在运行 bash)。它有效地输入命令,就好像您已经输入了一样。这很有用,因为它允许脚本更改 shell 中的环境变量。


运行脚本很简单,只需键入脚本的路径。Abc0是工作目录。因此,./script.sh将在工作目录中执行文件 script.sh。如果命令是单个文件(例如 script.sh) ,它将检查 PATH 变量中的所有文件夹以查找脚本。请注意,工作目录不在 PATH 中,所以你不能通过运行 script.sh在工作目录中执行文件 script.sh,你需要运行 ./script.sh(除非工作目录在 PATH 中,例如你可以在 /bin目录中运行 ls)。

源代码脚本不使用 PATH,只是搜索路径。请注意,source不是一个程序-否则它将无法更改当前 shell 中的环境变量。它实际上是一个内置的 bash 命令。搜索 /bin/usr/bin-你不会在那里找到一个 source程序。因此,要在工作目录中找到一个文件 script.sh的来源,只需使用 source script.sh


Sudo 是如何与之交互的?Sudo 接受一个程序,并作为 root 用户执行它。例如,sudo ./script.sh在子进程中执行 script.sh,但以 root 身份运行。

然而 sudo source ./script.sh是做什么的?还记得 source不是一个程序(而是一个内置的 shell)吗?但是 Sudo 需要一个程序名,所以它搜索一个名为 source的程序。它找不到,所以失败了。如果不创建新的子进程,就不可能以 root 用户身份来源化运行的文件,因为在程序启动后不能更改程序的运行程序(在本例中是 bash)。

我不知道你到底想要什么,但希望这能让你明白。


下面是一个具体的例子,在你的工作目录中创建一个包含以下内容的文件:

#!/bin/bash
export NEW_VAR="hello"
whoami
echo "Some text"

使用 chmod +x script.sh使其可执行。

现在看看 bash 会发生什么:

> ./script.sh
david
Some text
> echo $NEW_VAR


> sudo ./script.sh
root
Some text
> echo $NEW_VAR


> source script.sh
david
Some text
> echo $NEW_VAR
hello
> sudo source script.sh
sudo: source: command not found

您正在尝试做的事情是不可能的; 您当前的 shell 是在您的常规用户 ID 下运行的(即没有 root 用户,sudo将给您提供访问权限) ,以及 无法授予它 root 访问权限sudo所做的是创建一个以 root 身份运行的新 * sub * 进程。子进程可以只是一个常规程序(例如,sudo cp ...在根进程中运行 cp程序) ,也可以是一个根子 shell,但是 不能是当前的 shell。

(这实际上更加不可能,因为 sudo命令本身是作为当前 shell 的子进程执行的——这意味着在某种意义上,它已经太晚了,无法在“当前 shell”中执行任何操作,因为它不是在那里执行的。)

我不知道这是否违反了规定

sudo bash script.sh

似乎对我有用。

如果你真的想“使用 sudo 权限在当前 shell 中调用一个 shell 脚本”,你可以使用 exec来..。

用给定的程序替换 shell (执行它,而不是作为新进程)

我坚持将“执行”替换为“调用”,因为前者的含义包括创建一个新的过程和 ID,而后者是模棱两可的,为创造性留有空间,我对此已经很满意了。

考虑这个测试用例并仔细查看 pid 1337年

# Don't worry, the content of this script is cat'ed below
$ ./test.sh -o foo -p bar


User ubuntu is running...
PID TT       USER     COMMAND
775 pts/1    ubuntu   -bash
1408 pts/1    ubuntu    \_ bash ./test.sh -o foo -p bar
1411 pts/1    ubuntu        \_ ps -t /dev/pts/1 -fo pid,tty,user,args


User root is running...
PID TT       USER     COMMAND
775 pts/1    ubuntu   -bash
1337 pts/1    root      \_ sudo ./test.sh -o foo -p bar
1412 pts/1    root          \_ bash ./test.sh -o foo -p bar
1415 pts/1    root              \_ ps -t /dev/pts/1 -fo pid,tty,user,args


Take 'exec' out of the command and this script would get cat-ed twice. (Try it.)


#!/usr/bin/env bash


echo; echo "User $(whoami) is running..."
ps -t $(tty) -fo pid,tty,user,args


if [[ $EUID > 0 ]]; then
# exec replaces the current process effectively ending execution so no exit is needed.
exec sudo "$0" "$@"
fi


echo; echo "Take 'exec' out of the command and this script would get cat-ed twice. (Try it.)"; echo
cat $0

下面是使用 sudo -s的另一个测试

$ ps -fo pid,tty,user,args; ./test2.sh
PID TT       USER     COMMAND
10775 pts/1    ubuntu   -bash
11496 pts/1    ubuntu    \_ ps -fo pid,tty,user,args


User ubuntu is running...
PID TT       USER     COMMAND
10775 pts/1    ubuntu   -bash
11497 pts/1    ubuntu    \_ bash ./test2.sh
11500 pts/1    ubuntu        \_ ps -fo pid,tty,user,args


User root is running...
PID TT       USER     COMMAND
11497 pts/1    root     sudo -s
11501 pts/1    root      \_ /bin/bash
11503 pts/1    root          \_ ps -fo pid,tty,user,args


$ cat test2.src
echo; echo "User $(whoami) is running..."
ps -fo pid,tty,user,args


$ cat test2.sh
#!/usr/bin/env bash


source test2.src


exec sudo -s < test2.src

使用 sudo -s进行一个更简单的测试

$ ./exec.sh
bash's PID:25194    user ID:7809
systemd(1)───bash(23064)───bash(25194)───pstree(25196)


Finally...
bash's PID:25199    user ID:0
systemd(1)───bash(23064)───sudo(25194)───bash(25199)───pstree(25201)


$ cat exec.sh
#!/usr/bin/env bash


pid=$$
id=$(id -u)
echo "bash's PID:$pid    user ID:$id"
pstree -ps $pid


# the quoted EOF is important to prevent shell expansion of the $...
exec sudo -s <<EOF
echo
echo "Finally..."
echo "bash's PID:\$\$    user ID:\$(id -u)"
pstree -ps $pid
EOF

最简单的方法是输入:

sudo /bin/sh example.sh

即使第一个答案也是绝对精彩的,您可能只想在 sudo 下运行脚本。

您必须指定如下绝对路径:

sudo /home/user/example.sh
sudo ~/example.sh

(两个都在工作)

这行不通的!

sudo /bin/sh example.sh
sudo example.sh

它总会回来的

sudo: bin/sh: command not found
sudo: example.sh: command not found

这里的答案解释了为什么会发生这种情况,但我认为我应该加上我的简单方法来解决这个问题。首先,您可以将该文件猫到一个具有 sudo 权限的变量中。然后,可以计算变量,以便在当前 shell 中执行文件中的代码。

下面是读取和执行. env 文件的示例(ex Docker)

 sensitive_stuff=$(sudo cat ".env")
eval "${sensitive_stuff}"
echo $ADMIN_PASSWORD

没有 Sudo也行。

bash setup.sh