我正在编写一个简单的bash脚本,但我需要检查它是否以root权限运行。我知道可能有一种非常简单的方法来做到这一点,但我不知道怎么做。
只是为了明确:
有什么简单的方法可以编写一个名为foo.sh的脚本,使得命令
只是为了明确:
有什么简单的方法可以编写一个名为foo.sh的脚本,使得命令
./foo.sh
输出0
,而命令sudo ./foo.sh
输出1
?#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
id -u
我使用-u
来表示有效用户ID,而不是用-r
表示真实用户ID。权限由有效用户ID决定,而非真实用户ID。
/etc/passwd
以给定顺序包含以下用户名和用户ID 0
:
rootx
root2
已登录为root2
,给出以下结果:
whoami
: rootx
echo $USER
: root2
(如果程序是在空环境中启动的,则返回空字符串,例如env -i sh -c 'echo $USER'
)id -u
: 0
。如您所见,其他程序在此检查中失败,只有id -u
通过。更新后的脚本如下:
#!/bin/bash
if ! [ $(id -u) = 0 ]; then
echo "I am not root!"
exit 1
fi
sh
(dash
)作为解释器而不是bash
。但是很好的尝试,避免了另一个分支 :) - Lekensteyn[ -w /etc/shadow ]
。如果这是真的,你也可以成为root用户。 ;) - Kees Cook[ -w / ]
。思路是一样的。注意:在某些chroot环境中,[ -w /etc/shadow ]
会失败,因为/etc/shadow
不存在,所以使用/
的方法更可取。更好的方式是检查是否真正需要root权限。如果脚本需要写入/etc/someconfig
,只需检查该文件是否可写或者文件不存在且/etc
可写。 - Lekensteyn如 @Lekensteyn 所说,您应该使用有效的用户ID。您不需要在bash中调用id -u
:
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "You must be root to do this." 1>&2
exit 100
fi
@geirha在评论中的建议使用了算术计算:
#!/bin/bash
if (( EUID != 0 )); then
echo "You must be root to do this." 1>&2
exit 100
fi
((..))
来测试数字,而使用[[..]]
来测试字符串和文件,所以我会改为使用if ((EUID != 0)); then
,或者只需if ((EUID)); then
。 - geirhaEUID
应该变成 $EUID
。不要使用 (( $EUID != 0 ))
,而是使用 [ $EUID != 0 ]
。这样也适用于 dash
。 - LekensteynEUID
运行得很好。问题标记为bash
而不是dash
。命令env -i sh -c '[ $EUID != 0 ]'
失败了,但是env -i bash -c '(( EUID != 0 ))'
可以工作。顺便说一下,在Ubuntu上,dash
对于一些非ASCII字符无法正常工作。http://stackoverflow.com/questions/5160125/how-to-create-a-non-ascii-file-using-redirection-with-sh-c 现在已经是2011年了,还有人使用其他语言。 - jfs$EUID
的相关内容。由于这个原因,我已经改变了接受的答案。 - Thomas WardEUID:未找到
,要么出现[[: 未找到
。但是[ $(id -u) = 0 ]
运行得非常好。 - bleewhoami
命令来实现这一点,该命令会返回当前用户:#!/bin/bash
if [ `whoami` != 'root' ]
then
echo "You must be root to do this."
exit
fi
...
注意:在某些情况下,另一种方法是直接检查$USER
变量:
if [ $USER != 'root' ]
$USER
,特别是以这种方式。$USER
变量是由登录shell设置的,并不一定会传递给程序(env -i sh -c 'echo $USER'
)。以这种方式,$USER
为空,会导致语法错误。 - Lekensteyn$USER
是由 shell 设置的,它还是容易伪造的东西。Whoami 将返回实际用户。 - Paul de Vriezeid -u
是一个更优秀的解决方案。我认为这个答案可能会引导错误,不应该被接受。 - sam hocevar$USER
在你的shell中被解释,你的例子应该是 sudo sh -c 'echo $USER'
才有意义。 @George: 它错误地假设 whoami
对于UID 0总是返回 root
。 - sam hocevarEUID
环境变量,如果不存在,则调用标准的id
命令。if ((${EUID:-0} || "$(id -u)")); then
echo You are not root.
else
echo Hello, root.
fi
function amIRoot() {
! ((${EUID:-0} || "$(id -u)"))
}
id -u
完全相同。请点击此处查看基准测试脚本以及结果:https://pastebin.com/srC3LWQy - Vlastimil Burián((${EUID:-0} || "$(id -u)"))
总是运行 id -u
*,就像 ((1 || $(echo hi >&2; echo 1)))
和 ((0 || $(echo hi >&2; echo 1)))
都会打印出 hi
。在 shell 算术 之外,&&
和 ||
是控制操作符;在 a || "$(b)"
中,只有当 "$(b)"
运行时,b
才会运行。大多数扩展,包括命令替换,都受控制操作符的短路语义约束。Shell 算术也有运算符,它们恰好被拼写为 &&
和 ||
,同样也会进行短路处理,例如 ((1 || 0/0))
不会报错,但是 shell 算术发生在嵌套命令替换展开之后。 - Eliah Kagan#!/bin/bash
[[ $(id -u) != 0 ]]
echo $?
-ne
(违反直觉:文本操作数用于数字比较)。 - Gonen#!/bin/bash
if [ "$(id -u)" == "0" ]
then
echo "I am root."
else
echo "I am not root."
fi
#!/bin/su root
#!/bin/bash
if ! [ $(id -u) = 0 ]; then
gksudo -w $0 $@
exit
fi
#here go superuser commands, e.g. (switch intel cpu into powersave mode):
echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo
cpupower frequency-set -g powersave
gksudo
,请使用 sudo apt-get install gksu
进行安装。
$UID
和id -ru
仍然为0,但$EUID
和id -u
不是。请参考getuid(2)
并决定您需要什么。 - David Foerster$UID
和$EUID
是bashism。仅符合POSIX标准的shell没有这些变量,您需要使用id(1)
代替。 - David Foersterif ((EUID)); then
,参考 @geirha 的评论。 - jfsecho $EUID
,会得到1000
(预期)。但是,运行sudo echo $EUID
会得到1000
(不是预期的结果)。另一方面,id -u
会给我返回1000
,而sudo id -u
会给我返回0
(两者都是预期的结果)。 - Andrew Ensleysudo
之前被替换。如果你运行sudo sh -c 'echo $EUID'
,你会看到你期望的结果。 - sourcenouveausudo sh -c 'echo $EUID'
给我一个空行。我应该看到0
。 - Andrew Ensley$EUID
是一个 Bashism(如上面 @DavidFoerster 所提到的),而你的/bin/sh
很可能是一个指向/bin/dash
而不是/bin/bash
的链接。sudo bash -c 'echo $EUID'
将会得到预期的结果。 - Adrian Günter/bin/bash
的链接,许多(甚至全部?)Bash 安装在以sh
形式调用时会运行在 POSIX 模式下。也就是说,它们会有意忽略 Bashisms。这对于编写符合 POSIX 标准的 shell 脚本来说是一个很有用的初步测试,但如果你使用sh -c
来延迟插值,可能会导致问题。 - anon[[ $EUID -ne 0 ]] && echo "非 root 用户" || echo "root 用户"
。 - fcole90