sudo使用哪种shell

4

非常抱歉,这可能是其他人已经问过但似乎谷歌无法解决的问题。我试图弄清楚正在调用哪个shell,因为我遇到了不一致的情况。如果我使用sudo,我的脚本就不能运行,但如果我使用sudo bash,它就可以工作。然而,当我使用sudo echo $0时,它显示bash。

cpu=$(cat /proc/cpuinfo | grep Revision | cut -d' ' -f 2-);
if [[ "a22082" = $cpu || "a02082" = $cpu ]]; then
    echo 'do stuff';
fi

如果我用#!/bin/sh指定命令解释器,它仍然会失败,但更加具体的#!/bin/bash则可以成功。我现在知道[[是bash特有的,但尽管如此响应中似乎sudo的默认shell不是bash。

1
等一下,我假设shbash不是同一个shell。当你指定错误的shell时,你为什么会指望它能工作呢? - Hasturkun
2
我个人认为在shebang中添加#!/bin/sh是一个好习惯,同时最好明确指定要使用的shell。 - jgr208
@EdHeal,我刚在Mac OS上尝试了一下(问题是关于Linux的,但仍然),bash似乎在sudo之前执行$(SHELL),因为我首先收到了“-bash:SHELL:找不到命令”的提示,然后才出现输入密码的提示。所以我猜测bash在没有sudo的情况下运行$(SHELL) - ForceBru
1
@jgr208:sh是Bourne Shell(兼容)shell,bash是Bourne Again Shell,它有自己的特点。请参见https://dev59.com/g2025IYBdhLWcg3w6aUX#5725402。我的观点是,如果您正在使用`bash`功能,请使用`#!/bin/bash`。 - Hasturkun
2
只需在你的脚本开头加上类似于 #!/bin/bash#!/usr/bin/env bash 的 shebang,一切都会正常工作。 - sotona
显示剩余4条评论
2个回答

15

简短回答: 没有默认解释器。您的脚本需要在顶部加上一个shebang行#!/bin/bash

详细回答: sudo不运行shell。它直接运行您传递给它的命令,没有中间shell。如果您想要一个shell,您需要显式地传递一个。

sudo echo $0
这个命令存在误导性,因为在调用sudo之前,你的shell会先展开$0。它会打印出当前的$0,而不是sudo环境中$0的值。
让我们比较一些命令:
  • sudo ls

    This executes the /bin/ls executable directly. There's no shell involved. The following commands will show when the distinction comes into play.

  • sudo ls /root/*

    The current shell expands the glob. If you can't access /root/ then the glob isn't expanded and you get ls: cannot access /root/*: No such file or directory.

  • sudo 'ls /root/*'

    This attempts to execute a program called ls /root/*. Literally, it's named * in the root sub-directory of ls  (ls with a trailing space). It fails with sudo: ls /root/*: command not found.

  • sudo ls '/root/*'

    This runs /bin/ls and passes it the literal string /root/*. There's no glob expansion. It fails with ls: cannot access /root/*: No such file or directory.

  • sudo bash -c 'ls /root/*'

    This executes /bin/bash and has it interpolate the ls /root/* command-line, expanding the glob. This one, finally, works, because we have an explicit shell to expand the glob, and we're doing the expansion within sudo instead of outside of it.


sudo a=e printenv 中,是谁将 a=e 解析为环境变量的呢? - Jiang YD
@JiangYD sudo 命令在执行前会处理变量赋值。 - John Kugelman
你的意思是sudo程序解析a=e字符串,然后使用解析后的环境调用printenv程序吗? - Jiang YD
是的,没错。 - John Kugelman

6

为了补充John Kugelman的有用答案,并回答了帖子标题所暗示的更一般的问题:

另外一件事情是:最好总是在脚本的开头加上一个shebang行,以明确控制它运行的shell。

sudo默认情况下不运行shell,但可以通过以下任一选项来运行shell:

  • -s(非登录shell)
    • 使用通过$SHELL环境变量指定的shell,如果已定义的话,否则使用用户密码数据库中定义的shell(/etc/passwords
  • -i(登录shell,始终使用用户的shell)
    • 使用用户密码数据库中定义的shell

换句话说:sudo使用当前用户默认的shell,除非对于-s,可以通过$SHELL进行覆盖

请参阅man sudo以获取详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接