如何让 sudo fork bash 而不是 sh?

如何让 sudo fork bash 而不是 sh?

根据须藤(8)

Process model 

当 sudo 运行命令时,它会调用 fork(2),如上所述设置执行环境,并在子进程中调用 execve 系统调用。

另外,我发现分叉的子进程使用sh.

因此,如果该命令是一个 bash 脚本,其中包含一些特定于 bash 的命令(例如source其中的命令),则将sh无法正确执行它。例如:

% 猫 /tmp/wibble
来源某物
% ls -l /tmp/wibble
-rwxr-xr-x 1 用户 用户 17 Aug 24 08:32 /tmp/wibble
% 获取密码 root
根:x:0:0:根:/根:/bin/bash
% /tmp/摆动
/tmp/wibble: 1: /tmp/wibble: 来源: 未找到
% /bin/bash /tmp/wibble ~ [pts/3.4028.1]
/tmp/wibble: 第 1 行: 某事: 没有这样的文件或目录
% /bin/dash /tmp/wibble
/tmp/wibble: 1: /tmp/wibble: 来源: 未找到
% /bin/sh /tmp/wibble
/tmp/wibble: 1: /tmp/wibble: 来源: 未找到
%回显$SHELL
/bin/zsh
% sudo /tmp/wibble
/tmp/wibble: 1: /tmp/wibble: 来源: 未找到
% sudo -s /tmp/wibble
/tmp/wibble: 1: /tmp/wibble: 来源: 未找到
% sudo -i /tmp/wibble
/tmp/wibble: 第 1 行: 某事: 没有这样的文件或目录
% 导出 SHELL=/bin/bash
% sudo /tmp/wibble
/tmp/wibble: 1: /tmp/wibble: 来源: 未找到
% sudo -s /tmp/wibble
/tmp/wibble: 第 1 行: 某事: 没有这样的文件或目录
% sudo -i /tmp/wibble
/tmp/wibble: 第 1 行: 某事: 没有这样的文件或目录
%

通常我们可以附加一个-s选项来sudo解决这个问题,如前面的示例所示,但我想知道为什么sudo使用sh默认值。这样可以配置到其他shell吗?

答案1

确保您的脚本以适当的#!-line 开头。

如果脚本是可执行的并且以例如

#!/bin/bash

(或者您系统上的任何路径bash),然后是脚本将要/bin/bash如果您键入,则将被解释为sudo script,就像 Python 脚本/usr/bin/python如果其第一行是则将被解释为#!/usr/bin/python

sh是 shellbash还是其他 shell 的问题在这里并不有趣。一般来说,假设每种类型的 shell 都有自己互斥的脚本语言并使用#!-line 来准确指定您编写脚本的解释器。例如,如果您仅使用 POSIX 语法和句法编写可移植脚本,请使用#!/bin/sh,但#!/bin/bash如果您使用bash的数组或此 shell 扩展 POSIX shell 的其他内容,请使用 。

当文本文件不以#!,开头时,/bin/sh用作后备。这与 无关sudo

在更新的问题中,您显示了对没有 -line 的脚本的多次调用#!。它们都失败,要么是因为解释器不理解source命令 ( source: not found),要么是因为它找不到文件 ( something: No such file or directory)。

总结一下:始终使用 -line 指定脚本的解释器#!

另外:使用时source,请指定源文件的路径,即使它只是./something,否则可能会从$PATH.

有关的:

答案2

更新:问题已被大量修改,所以必须是我的答案。
虽然我发现没有标准定义什么被认为是“脚本”,但只要它由 shell 执行,即使只是包含命令列表的文件也可能是“脚本”。因此,应该小心,如果脚本顶部没有指定 shell,则将采用默认行为(sh)。
旧答案:
如果sh当前系统上不是 bash,脚本应该失败,因为 bashisms 不会被理解。
我们来做个实验吧!

~/Downloads/test$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4  8月 31  2016 /bin/sh -> dash

首先,确认sh不是bash
bash.sh将要利用bash.它调用另一个 bash 脚本,使用sudo.

:~/Downloads/test$ cat bash.sh 
#!/bin/bash

sudo ./sudo_bash.sh

dash.sh是一个破折号脚本,它表明((i++))根据你的话, bashism 应该失败。

:~/Downloads/test$ cat dash.sh 
#!/bin/sh

i=0
((i++))
echo $i

我们来确认一下

:~/Downloads/test$ ./dash.sh 
./dash.sh: 4: ./dash.sh: i++: not found
0
:~/Downloads/test$ 

美丽地失败了。现在,sudo_bash.sh是一个 bash 脚本。我们将使用 sudo 命令从 bash.sh 执行它,正如你所说,如果它真的被分叉了,sh那么它也应该失败。

:~/Downloads/test$ cat sudo_bash.sh 
#!/bin/bash

i=0
((i++))
echo $i

:~/Downloads/test$ ./bash.sh 
[sudo] password for cs-server: 
1
:~/Downloads/test$

执行成功。那就证明新环境不能用了/bin/sh

I'd like to know why sudo uses sh as default.  

历史上第一个 shell 是 sh,因此出于兼容性原因仍保留名称。

Is it so that it can be configured to other shells?

当然,只需更改 sh 的符号链接即可

:~/Downloads/test$ cat text_file 
i=0
((i++))
echo $i
:~/Downloads/test$ chmod +x text_file 
:~/Downloads/test$ sudo ln -sf bash /bin/sh
:~/Downloads/test$ sudo ./text_file
1
:~/Downloads/test$ sudo ln -sf dash /bin/sh
:~/Downloads/test$ sudo ./text_file
./text_file: 2: ./text_file: i++: not found
0

相关内容