如何避免根壳嵌套? (POSIX)

如何避免根壳嵌套? (POSIX)

考虑下面的 Bash 别名,我很快就想到了这个,但我没有时间进一步挖掘:

alias su='sudo -s'

请注意,我正在运行 Bash,但我希望该解决方案是可移植的,因为我可能会在某个时候将其发布到 GitHub 上进行共享。

人们可能遇到的问题是在已经 root 的情况下运行它(该别名)。

演示:

$ su
[sudo] password for vlastimil:                
# su
# su
# 
exit
# 
exit
# 
exit
$ 

有没有办法避免嵌套的 shell 会话?

重要提示:我为我的用户和根用户使用相同的别名文件,而不是分开的。该解决方案必须是可移植的 (POSIX)。

答案1

susudo -s是具有不同 API、语义和行为的不同命令,您不应将其中一个命令别名为另一个命令。

在这里,您似乎想要一个命令来启动的root登录 shell,但仅当从非特权 shell 调用时,所以我会编写一个名为的脚本,例如:rootsudorootshell

#! /bin/sh -

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

[ "$#" -eq 0 ] || die "Usage: $0

Starts a root shell, no argument accepted."

[ "$(id -u)" -eq 0 ] && die "You're already superuser!"

exec sudo -s

添加-u rootsudo命令(或系统上 uid 0 的用户名),如果这不是系统sudo配置中的默认目标用户。

或者,如果您不想创建脚本,请通过包装该代码以rootshell() (<that-code>)将其添加到您的 shell rc 文件中,使其成为 shell 函数(更改$0为函数名称,因为并非所有 shell 都将函数名称放入 中$0)。

答案2

简单的解决方案,shell 别名

alias su='[ $(id -u) -ne 0 ] && sudo -s || echo Already root...'

  • POSIX 兼容,这意味着如果您将其复制粘贴到dash或者我想几乎任何其他支持 shell 的别名,您应该得到相同的行为。

  • 这也是我EUID完全避免和直接进行价值比较的原因。


演示:

$ su
[sudo] password for vlastimil:                
# su
Already root...
# su
Already root...
# 
exit
$ 

考虑到我使用sudo -s,我附上sudo -s与其他变体的比较


高级解决方案,shell 脚本 (POSIX)

由于我使用上面的伪解决方案(别名)很长一段时间(几年),我也意识到了它的缺点。这就是为什么我刚刚将脚本发布到代码审查基于斯蒂芬·查泽拉斯, 这问题以及各自的回答可以在那里找到。我在这里放置了我打算从现在开始使用的脚本:

#!/bin/sh

set -o nounset -o errexit

error()
{
    printf >&2 '%s\n' "$@"
    exit 1
}

is_root()
{
    [ "$(id -u)" -eq 0 ]
}

start_root_shell()
{
    exec sudo -s
}

if [ "$#" -gt 0 ]
then
    error "Usage of $(basename "$0") script:" \
    '' \
    'Starts a root shell, no argument accepted.'
fi

if is_root
then
    error 'You are already superuser!'
fi

start_root_shell

谢谢斯蒂芬·查泽拉斯为我指明了正确的方向!

答案3

这个答案分为两个部分,都依赖于编辑文件sudoers。 (我不确定如何通过 POSIX 合规性来回答这个问题,因为您的示例中既没有sudobash没有使用 POSIX。但是,该解决方案应该可以跨使用这些工具的系统移植。)

  1. 您可以通过在文件中设置布尔变量来简化使用sudo并避免使用别名。您现在可以使用来访问 root shell,而不是.shell_noargs/etc/sudoerssudosudo -s

  2. 某些 shell(例如 )bash允许您通过变量(例如 )来跟踪 shell 级别$SHLVL。这可以通过sudo调用以及简单地键入来跟踪bash。将其添加到 shell 提示符中将帮助您确定当前有多少层嵌套。

创建我们自己的sudoers文件,而不是编辑系统提供的文件:

sudo EDITOR=nano visudo -f /etc/sudoers.d/local

将这些行添加到文件中并保存

# Allow sudo with no args to create a shell
Defaults        shell_noargs

# Allow bash to share its nesting level
Defaults        env_check+="SHLVL"

对于bash,转到您的~/.bashrc(可能是~/.bash_profile~/.profile)并找到定义 的行PS1。修改它以包含$SHLVL.例如,在我的 Debian 系统上它的设置如下:

PS1='${debian_chroot:+($debian_chroot)}\u@\h:\W\$ '

我会修改它以包括$SHLVL这样的内容:

PS1='${debian_chroot:+($debian_chroot)}\u@\h[$SHLVL]:\W\$ '

最后,重复编辑 root 的配置文件。

请注意,如果您使用的 shellbash不提供此功能,$SHLVL那么实现起来很简单假如shell 每次启动时都会运行一个配置文件。 (sh不幸的是,POSIX 没有。)

相关内容