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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18809614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:50:38  来源:igfitidea点击:

Execute a shell script in current shell with sudo permission

linuxbashshell

提问by shar

For executing a shell script in current shell, we need to use a period .or a sourcecommand. But why does it not work with a sudo permission?

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

I have a script with execute permission called setup.sh. When I use a period, I get this:

我有一个名为setup.sh. 当我使用一段时间时,我得到了这个:

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

The source command also produces a similar error. Am I missing out something? What should I do to run the script with sudo permission in the same shell?

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

Thanks in advance..

提前致谢..

采纳答案by Gordon Davisson

What you are trying to do is impossible; your current shell is running under your regular user ID (i.e. without root the access sudowould give you), and there is no way to grant it root access. What sudodoes is create a new *sub*process that runs as root. The subprocess could be just a regular program (e.g. sudo cp ...runs the cpprogram in a root process) or it could be a root subshell, but it cannotbe the current shell.

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

(It's actually even more impossible than that, because the sudocommand itself is executed as a subprocess of the current shell -- meaning that in a sense it's already too late for it to do anything in the "current shell", because that's not where it executes.)

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

回答by loxxy

Basically sudo expects, an executable (command) to follow & you are providing with a .

基本上 sudo 期望,要遵循的可执行文件(命令)并且您正在提供 .

Hence the error.

因此错误。

Try this way $ sudo setup.sh

试试这个方法 $ sudo setup.sh



回答by David Miani

I think you are confused about the difference between sourcing and executing a script.

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

Executing a script means creating a new process, and running the program. The program can be a shell script, or any other type of program. As it is a sub process, any environmental variables changed in the program will not affect the shell.

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

Sourcing a script can only be used with a bash script (if you are running bash). It effectively types the commands in as if you did them. This is useful as it lets a script change environmental variables in the shell.

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



Running a script is simple, you just type in the path to the script. .is the current directory. So ./script.shwill execute the file script.shin the current directory. If the command is a single file (eg script.sh), it will check all the folders in the PATH variable to find the script. Note that the current directory isn't in PATH, so you can't execute a file script.shin the current directory by running script.sh, you need to run ./script.sh(unless the current directory is in the PATH, eg you can run lswhile in the /bindir).

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

Sourcing a script doesn't use the PATH, and just searches for the path. Note that sourceisn't a program - otherwise it wouldn't be able to change environmental variables in the current shell. It is actually a bash built in command. Search /binand /usr/bin- you won't find a sourceprogram there. So to source a file script.shin the current directory, you just use source script.sh.

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



How does sudo interact with this? Well sudo takes a program, and executes it as root. Eg sudo ./script.shexecutes script.shin a sub process but running as root.

sudo 如何与此交互?那么 sudo 需要一个程序,并以 root 身份执行它。例如,在子进程中sudo ./script.sh执行script.sh但以 root 身份运行。

What does sudo source ./script.shdo however? Remember sourceisn't a program (rather a shell builtin)? Sudo expects a program name though, so it searches for a program named source. It doesn't find one, and so fails. It isn't possible to source a file running as root, without creating a new subprocess, as you cannot change the runner of a program (in this case, bash) after it has started.

sudo source ./script.sh但是有什么作用呢?记住source不是一个程序(而是一个内置的shell)?不过,Sudo 需要一个程序名称,因此它搜索名为source. 它没有找到,所以失败了。不可能在不创建新子进程的情况下获取以 root 身份运行的文件,因为您无法在程序启动后更改运行程序(在本例中为 bash)。

I'm not sure what you actually wanted, but hopefully this will clear it up for you.

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



Here is a concrete example. Make the file script.shin your current directory with the contents:

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

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

Make it executable with chmod +x script.sh.

使用chmod +x script.sh.

Now observe what happens with bash:

现在观察 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

回答by JaseC

I'm not sure if this breaks any rules but

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

sudo bash script.sh

seems to work for me.

似乎对我有用。

回答by Bruno Bronosky

If you really want to "ExecuteCall a shell script in current shell with sudo permission" you can use execto...

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

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

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

I insist on replacing "execute" with "call" because the former has a meaning that includes creating a new process and ID, where the latter is ambiguous and leaves room for creativity, of which I am full.

我坚持用“调用”代替“执行”,因为前者的含义包括创建一个新的进程和ID,后者是模棱两可的,留下了创造力的空间,我对此很满意。

Consider this test case and look closely at pid 1337

考虑这个测试用例并仔细查看 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 "
$ 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
" "$@" fi echo; echo "Take 'exec' out of the command and this script would get cat-ed twice. (Try it.)"; echo cat
$ ./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

Here is another test using sudo -s

这是另一个测试使用 sudo -s

sudo /bin/sh example.sh

And a simpler test using sudo -s

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

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

回答by Simon Hayter

Easiest method is to type:

最简单的方法是键入:

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

回答by Martin Kova?

Even the first answer is absolutely brilliant, you probably want to only run script under sudo.

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

You have to specify the absolute path like:

您必须指定绝对路径,例如:

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

(both are working)

(两人都在工作)

THIS WONT WORK!

这行不通!

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

It will always return

它总会回来

##代码##

回答by Ohiovr

The answers here explain why it happens but I thought I'd add my simple way around the issue. First you can cat the file into a variable with sudo permissions. Then you can evaluate the variable to execute the code in the file in your current shell.

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

Here is an example of reading and executing an .env file (ex Docker)

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

##代码##