3

I'm writing a script to configure new debian installs while finding the best solution to confirming that a user exists in the script, the best way I found gives me wierd output.

PROBLEM:

id -u $var and id -u $varsome give the same output even though var has a value (the username) and varsome has no value

[19:49:24][username] ~ ~↓↓$↓↓ var=`whoami`
[19:53:38][username] ~ ~↓↓$↓↓ id -u $var
1000
[19:53:42][username] ~ ~↓↓$↓↓ echo $?
0
[19:53:49][username] ~ ~↓↓$↓↓ id -u $varsome
1000
[19:09:56][username] ~ ~↓↓$↓↓ echo $?
0
[20:10:18][username] ~ ~↓↓$↓↓ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
Licens GPLv3+: GNU GPL version 3 eller senere <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
[20:27:08][username] ~ ~↓↓$↓↓ cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

I got the command from this question on stackoverflow: Check Whether a User Exists

QUESTIONS:

  • What is happening here?
  • Is there a better way you can find to verify a user exist's in a script?
  • Pointers on the script well appreciated
ilkkachu
  • 138,973

2 Answers2

9

Since the variable expansion wasn't quoted, the empty word that results from $varsome being expanded is removed completely.

Let's make a function that prints the number of arguments it gets and compare the quoted and non-quoted case:

$ args() { echo "got $# arguments"; }
$ var=""
$ args $var
got 0 arguments    
$ args "$var"
got 1 arguments

The same happens in your case with id: id -u $var is exactly the same as just id -u when var is empty. Since id doesn't see a username, it by default prints the current user's information.

If you quote "$var", the result is different:

$ var=""
$ id -u "$var"
id: ‘’: no such user

With that fixed, you can use id to find if a user exists. (We don't need the outputs here though, so redirect them away.)

check_user() { 
    if id -u "$1" >/dev/null 2>&1; then
        echo "user '$1' exists"
    else
        echo "user '$1' does not exist"
    fi
}
check_user root
check_user asdfghjkl

That would print user 'root' exists and user 'asdfghjkl' does not exist.


This is a bit of the inverse of the usual problems that come from the unexpected word splitting of unquoted variables. But the basic issue is the same and fixed by what half the answers here say: always quote the variable expansions (unless you know you want the unquoted behaviour).

See:

ilkkachu
  • 138,973
1

The command id -u will give you the id of the current user. The command id -u user will give you the id of that user.

Now in your example, you use

var=`whoami`
id -u $var

The command whoami returns the current user. So id -u current_user will return the id of the current user, and id -u will also return the id of the current user.

Edit

Note that backticks are deprecated an it is recommended to write $(whoami) instead, for example:

var=$(whoami)
id -u $var
slm
  • 369,824
RalfFriedl
  • 8,981
  • @RalfFriedl Thank you for the answer, yes this is true, but nothing new here, my point was that the variable that had no value was giving the same output – somethingSomething Aug 14 '18 at 21:08
  • @somethingSomething Yes, and I explained why it gives the same output inyour case. If you already knew that, then what was the question? – RalfFriedl Aug 14 '18 at 21:10