使用 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.sh
或source setup.sh
或. setup.sh
来完成。然而,因为后两种是 bash 内置的,所以只有第一种形式可以与 需要可执行文件的 sudo 一起使用。您可以使用sudo which bash
和sudo which source
和sudo 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 脚本的主要内容,如果未能解决你的问题,请参考以下文章