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

Posted

技术标签:

【中文标题】使用 sudo 权限在当前 shell 中执行 shell 脚本【英文标题】:Execute a shell script in current shell with sudo permission 【发布时间】:2013-09-19 12:23:59 【问题描述】:

为了在当前 shell 中执行 shell 脚本,我们需要使用句点 .source 命令。但为什么它不适用于 sudo 权限?

我有一个名为setup.sh 的具有执行权限的脚本。当我使用句号时,我得到这个:

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

source 命令也会产生类似的错误。我错过了什么吗?我应该怎么做才能在同一个 shell 中运行具有 sudo 权限的脚本?

提前谢谢..

【问题讨论】:

尽管答案很好,但我认为这个问题几乎只是一个错字。删除第一个单独的句点。 @beroe 你错了。问题不是错字。如果setup.sh 没有执行权限,那么您必须使用 bash 显式解释它。这可以通过bash setup.shsource setup.sh. setup.sh 来完成。然而,因为后两种是 bash 内置的,所以只有第一种形式可以与 需要可执行文件sudo 一起使用。您可以使用sudo which bashsudo which sourcesudo which . 来查看sudo 会找到什么。 @BrunoBronosky 在我看来(看起来)就像他们试图将第一个孤点作为命令运行一样。由于这指定了当前工作目录,而不是命令,因此它会引发该错误。如果他们输入./setup.sh,那就另当别论了。 @beroe 一个单独的点一个shell命令——具体来说,它是一个shell内置命令,相当于source命令(也是一个内置命令)。 【参考方案1】:

我不确定这是否违反任何规则,但

sudo bash script.sh

似乎对我有用。

【讨论】:

【参考方案2】:

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

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

获取脚本只能与 bash 脚本一起使用(如果您正在运行 bash)。它有效地键入命令,就像您执行它们一样。这很有用,因为它允许脚本更改 shell 中的环境变量。


运行脚本很简单,只需输入脚本的路径即可。 . 是当前目录。所以./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)的运行程序。

我不确定您真正想要什么,但希望这会为您解决问题。


这是一个具体的例子。在当前目录中创建文件script.sh,内容如下:

#!/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

【讨论】:

【参考方案3】:

你想做的事是不可能的;您当前的 shell 在您的常规用户 ID 下运行(即没有 root 权限,sudo 会给您),并且无法授予它 root 权限sudo 所做的是创建一个以 root 身份运行的新 *sub* 进程。子进程可能只是一个常规程序(例如sudo cp ... 在根进程中运行cp 程序)或者它可能是根子shell,但它不能是当前shell。

(实际上比这更不可能,因为sudo命令本身是作为当前shell的子进程执行的——这意味着从某种意义上说,它在“当前shell”中做任何事情已经太晚了,因为那不是它执行的地方。)

【讨论】:

当@JaseC 下面的答案似乎对我有用时,我不确定为什么这是公认的答案。 sudo bash myscript.sh 完全符合我的要求,以及 OP 似乎要求的。 @dalesikkema:sudo bash myscript.sh 将在子 shell 中运行脚本,而不是在当前 shell 中。如果这适用于您的情况,那就太好了——但这个特殊的问题是关于在当前 shell 中以 root 身份运行脚本。 整个前提含糊不清,因为选词不准确。 “要在当前 shell 中执行 shell 脚本,我们需要使用句点” 不,那个句点不会执行,它会获取、插入、读取或解释。执行意味着不同的PID。所以,我们不清楚他们是否/为什么会关心他们当前 shell 的 PID。【参考方案4】:

基本上 sudo 需要一个可执行文件(命令),并且您提供的是 .

因此错误。

试试这个方法$ sudo setup.sh


【讨论】:

【参考方案5】:

如果你真的想“执行在当前 shell 中调用具有 sudo 权限的 shell 脚本”你可以使用 exec 来...

replace the shell with a given program (executing it, not as new process)

我坚持用“调用”代替“执行”,因为前者的含义包括创建一个新的流程和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

【讨论】:

我今天投了反对票,没有任何评论。这对任何人有什么帮助?享受失去您的 2 点声望点。 (没错。你的声誉下降 2 分才能给我 1 票。) 有点混乱....下一次,把命令和输出简单明了,而不是描述你做了什么。这将有助于解释你的脚本中使用的命令,并不是每个人都和你一样熟练。【参考方案6】:

它可以在没有“sudo”的情况下工作。

bash setup.sh

【讨论】:

【参考方案7】:

即使第一个答案也非常出色,您可能只想在 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

【讨论】:

【参考方案8】:

最简单的方法是输入:

sudo /bin/sh example.sh

【讨论】:

【参考方案9】:

这里的答案解释了它发生的原因,但我想我会添加我的简单方法来解决这个问题。首先,您可以将文件放入具有 sudo 权限的变量中。然后您可以评估该变量以在当前 shell 中执行文件中的代码。

这是一个读取和执行 .env 文件的示例(前 Docker)

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

【讨论】:

以上是关于使用 sudo 权限在当前 shell 中执行 shell 脚本的主要内容,如果未能解决你的问题,请参考以下文章

sudo指令和/etc/sudoers文件说明

sudo命令使用的几个场景

Linux创建用户配置sudo权限

sudo和root权限有啥区别,为啥有的命令sudo无法执行,只能root执行?

linux sudo时说找不到cd命令, 怎么解决

sudo命令使用的几个场景