Testing for root in POSIX shell

Published: Wednesday, Sep 10, 2008 Last modified: Monday, Dec 9, 2024

In order of preference. The last code snippet is arguably the best.

Do not depend on bloated BASH extensions! Use the bourne shell and lint/check with the checkbashisms tool from Debian devscripts.

#!/bin/sh

$USER could be forged with certain shells! Also dangerous with su

if test "$USER" != "xroot"
then
	echo not root
	exit 1
fi

Ugly !

[ `id -u` -ne 0 ] && echo "not root" && exit 1

Using test is better, though still UGLY to string it along one line like that. And if you decide to do a else clause with ||, bugs can easily result.

test "x$(whoami)" != "xroot" && echo "not root" && exit 1

Old original bourne shell did not know test prepending !

if ! test `id -u` = 0; then
	echo "not root" > /dev/stderr # /dev/stderror is not portable!
	exit 1
fi

Old bourne shells did not know semi-colons either. Be careful to keep whitespace on the inner area of the square brackets and notice we are using a string comparison without quoting.

if [ `id -u` -ne 0 ]; then
	echo >&2 "not root" # this works, but is not as readable as appending the stderr
	exit 1
fi

Old bourne shells did not know $() subshell. Notice we are using numeric comparison with strings, which could lead to problems on certain shells.

if test "x$(whoami)" != "xroot" # in case whoami returns empty value
then
	echo "not root" >&2
	exit 1
fi

Easy to read POSIX shell, though missing quotes which is sadly needed always to “play safe” :(

if test `id -u` != 0
then
	echo "not root" >&2
	exit 1
fi

Modern shell style with quotes and no backticks

if [ "$(id -u)" -ne "0" ] # string comparison is better in shell as argument lists are strings
then
	echo "not root" >&2
	exit 1
fi

Old Bourne POSIX shell flavour. Safe, portable and compatible and a bit too verbose for my liking.

ID=`id -u` # id is _slightly_ better than whoami, though less readable imo
if test "x$ID" -ne "x0"
then
	echo "not root" # you don't have to output to stderr if you don't want to
	exit 1
fi

Using test is a better practice than using square brackets. Here I assume id returns something. In certain rare environments you cannot make this assumption!

if test "$(id -u)" -ne "0"
then
	echo "not root" >&2
	exit 1
fi