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

时间:2013-09-15 06:38:28

标签: linux bash shell

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

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

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

source命令也会产生类似的错误。我错过了什么吗?如何在同一个shell中使用sudo权限运行脚本?

提前致谢..

9 个答案:

答案 0 :(得分:93)

我不确定这是否会破坏任何规则,但

sudo bash script.sh

似乎对我有用。

答案 1 :(得分:31)

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

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

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


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

采购脚本不使用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

答案 2 :(得分:29)

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

(实际上甚至比这更不可能,因为sudo命令本身作为当前shell的子进程执行 - 这意味着在某种意义上说它已经为时已晚,无法在“当前shell“,因为那不是它执行的地方。”

答案 3 :(得分:5)

基本上sudo期望,可执行(命令)跟随&您正在提供.

因此错误。

试试$ sudo setup.sh


答案 4 :(得分:0)

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

  

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

我坚持用“call”替换“execute”,因为前者的含义包括创建一个新的进程和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

答案 5 :(得分:0)

即使第一个答案绝对是绝妙的,您可能只想在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

答案 6 :(得分:0)

这里的答案解释了为什么会发生这种情况,但我想我将针对此问题添加简单的方法。首先,您可以将文件分类为具有sudo权限的变量。然后,您可以评估该变量以执行当前Shell中文件中的代码。

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

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

答案 7 :(得分:0)

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

bash setup.sh

答案 8 :(得分:-1)

最简单的方法是键入:

  • sudo /bin/sh example.sh