Testing for root in POSIX shell

Wednesday, Sep 10, 2008

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