在sudo调用的Bash脚本中识别用户
1. 概述
有时,当我们编写一个 shell 脚本时,我们想知道当前登录用户是谁。
通常,我们可以通过读取*$USER变量或调用whoami 命令来获取信息。但是,如果使用sudo *调用 shell 脚本,这种方法将不起作用。
在本教程中,我们将仔细研究这个问题。此外,我们将讨论在 shell 脚本中检索登录用户的技术,即使用户使用sudo命令调用脚本也是如此。
2. 问题介绍
2.1. 理解问题
让我们通过一个简单的例子来理解这个问题:
$ cat ./get_user.sh
#!/bin/bash
echo "Get the current login user by reading the \$USER variable: "$USER
echo "Get the current login user by the whoami command: "$(whoami)
在上面的脚本中,我们有几个echo命令。他们通过$USER环境变量和命令 whoami 打印当前登录用户。
如果我们以普通用户kent登录并调用脚本:
kent$ ./get_user.sh
Get the current login user by reading the $USER variable: kent
Get the current login user by the whoami command: kent
正如我们所料,两个echo命令都将kent打印为当前登录用户。但是,让我们看看当我们使用sudo命令调用脚本时它是否仍然有效:
kent$ sudo ./get_user.sh
[sudo] password for kent:
Get the current login user by reading the $USER variable: root
Get the current login user by the whoami command: root
这一次,在我们输入密码后,我们看到两个echo命令都打印了root。**这里,root是执行脚本的有效用户。但是,它不是登录用户。**当前登录用户是kent。我们正在寻找一种在 shell 脚本中识别当前登录用户的方法。
2.2. 为什么who命令不是解决方案
说到登录用户,我们可能会想到方便的 who 命令。
让我们执行who命令,看看它打印了什么:
kent$ who
kent tty7 2021-06-30 22:58 (:0)
who命令可以列出当前登录的用户。因此,列出了用户 kent。这似乎是我们正在寻找的确切答案。
在我们的脚本中,我们可以解析who命令的输出并获取当前登录用户。这个想法可能适用于这个例子。但是,它使脚本不稳定。
让我们回顾一下 who输出。我们只有一条输出线。这是因为目前只有用户kent登录了系统。但是,Linux 是一个多用户系统。所以现在,让我们通过另一个用户guest登录系统并再次 启动who命令:
kent$ who
kent tty7 2021-06-30 22:58 (:0)
guest tty4 2021-07-04 20:26
正如我们所见,所有登录用户都由who命令列出。也就是说,一旦我们的脚本被sudo命令执行,我们就不能依靠 who命令来区分是哪个用户执行了脚本。
当我们想要获取当前登录用户时,这也是一个常见的陷阱。接下来,让我们找出问题的稳定解决方案。
3. 使用logname命令
logname 是*coreutils *包的成员。因此,它适用于所有 Linux 发行版。
logname命令打印用户的登录名。
让我们看看它是否可以解决我们的问题。首先,让我们编写一个新的 shell 脚本:
$ cat by_logname.sh
#!/bin/bash
echo "The login user is "$(logname)
接下来,让我们在使用和不使用 sudo 的情况下执行 shell 脚本:
kent$ ./by_logname.sh
The login user is kent
kent$ sudo ./by_logname.sh
[sudo] password for kent:
The login user is kent
如上面的输出所示,我们的脚本在两种情况下都输出了kent。因此,使用logname命令已解决了该问题。
4. 使用*$SUDO_USER*变量
当我们使用 sudo命令时,调用sudo的用户的原始登录名将存储在变量$SUDO_USER*中。*
让我们创建一个小脚本来测试它:
kent$ cat by_sudo_user.sh
#!/bin/bash
echo "The login user is $SUDO_USER"
现在,我们使用sudo命令执行脚本 :
$ sudo ./by_sudo_user.sh
[sudo] password for kent:
The login user is kent
伟大的!它报告原始登录用户kent。
但是,只有在使用sudo调用我们的脚本时才会设置*$SUDO_USER变量。如果普通用户直接调用脚本,则$SUDO_USER*变量为空:
kent$ ./by_sudo_user.sh
The login user is
为了使我们的脚本在这两种情况下都能正常工作,我们可以在脚本中使用 Bash 的参数替换 ${parameter:-default}。
** ${parameter:-default}表示,如果参数已经设置,那么我们取它的值。否则,我们采用 默认值。**
这里,默认部分可以是固定值、shell 变量或命令替换 等。我们将在后面的示例中看到它们的作用。
让我们回到我们的脚本。我们将首先检查 $SUDO_USER变量:
- 如果已设置,则表示用户使用sudo调用脚本,$SUDO_USER中的值为登录用户
- 否则,如果*$SUDO_USER变量未设置,我们可以获取$USER变量的值或whoami*命令的输出
接下来,让我们更改脚本以涵盖此检查:
kent$ cat ./by_sudo_user.sh
#!/bin/bash
echo "The login user is ${SUDO_USER:-$USER}"
echo "The login user is ${SUDO_USER:-$(whoami)}"
在上面修改后的脚本中,我们展示了两种替代方法来解决参数替换的使用问题。
最后,让我们测试一下它是否像我们预期的那样工作:
kent$ ./by_sudo_user.sh
The login user is kent
The login user is kent
kent$ sudo ./by_sudo_user.sh
[sudo] password for kent:
The login user is kent
The login user is kent
上面的输出显示我们的脚本适用于这两种情况。这样,问题就解决了。