0

I am trying to use useradd. I found an example of something I'd like to try and incorporate, though I can't understand specific parts.

Here is the example in entirety:

if [ $(id -u) -eq 0 ]; then
read -p "Enter username : " username
read -s -p "Enter password : " password
egrep "^$username" /etc/passwd >/dev/null
if [ $? -eq 0 ]; then
    echo "$username exists!"
    exit 1    

I understand the basics what is going on, but specifically:

[ $(id -u) -eq 0 ];

and

[ $? -eq 0 ];

I'm guessing a variable is being made within the brackets. But I've been stumped deciphering their purpose or meaning.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Gee_k
  • 27

2 Answers2

0

From man:

-u, --user

        print only the effective user ID

id -u will print the ID of the user. The script is restricted to root user which UID is 0.

$? exit status of the previously executed command.

Siva
  • 9,077
  • OK! I get it, thanks. So in this case will $? looking for the exit status of egrep? Zero meaning egrep matched a user, triggering '$username exists!`? – Gee_k Mar 27 '19 at 06:54
  • @user7055355 exit status 0 means egrep execution is success. – Siva Mar 27 '19 at 08:38
0

The id utility, when used with its -u option, will output the UID of the current user. If that UID is zero, then the user is the root user. Only the root user should add new users.

Therefore, the script tests the UID of the user running the script agains zero and only performs the privileged actions (not shown in the script in the question) if the user is root.

An arguably better way to handle this in the script, if the whole script requires root, is to check whether the UID is non-zero at the start and exit with an error if it is:

if [ "$(id -u)" -ne 0 ]; then
    echo 'You are not root.  Try again with sudo.' >&2
    exit 1
fi

As for the $?, it's a special shell variable that always contains the exit status of the most recently executed command. It is very rare to need to use this directly, as if is more than capable of working directly with grep:

if grep -q "^$username" /etc/passwd; then
    printf 'User "%s" already exists\n' "$username" >&2
    exit 1
fi

Here, if will use the exit status of grep. We use grep with -q to stop it from producing any output and from parsing the whole file past any first match. It just returns an exit status that if will use. We also don't need egrep as the regular expression is not an extended regular expression (egrep is identical to grep -E).

Note also that diagnostic messages should be written to the standard error stream. You may do this by redirecting your messages with >&2. Also, printf is preferred over echo when outputting variable data.

If you are on a system where a directory service such as NIS or LDAP is used, grepping for an existing user in /etc/passwd may not be useful as the actual users may well be stored in a separate database.

On such systems, it may be better to use getent passwd "$username" (this would work on non-NIS/LDAP systems too). This would return the password database entry for the particular user, or exit with a non-zero exit status, which means we could use that in our test:

if getent passwd "$username" >/dev/null; then
    printf 'User "%s" already exists\n' "$username" >&2
    exit 1
fi

Just note that useradd can't add users to a NIS or LDAP database...

Although, strictly speaking nothing of the above should really be needed as useradd should not do anything useful if the current user is not root or if the user being added already exists.

Kusalananda
  • 333,661