Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi Peeps,

Can you tell me the quickest way to check if a user exists on my *nix box?

I am currently using the following code:
if(defined(getpwnam($username))) { $message = $message.'<p>The Chosen Username Already Exists.</p>'; $found_err = 1; }
Is There a quicker way than this, or is this as good as it gets?


Also, i want to perfom the fastest possible search of a file (sample shown below), to see if it contains the the contents of $username in the the first field (myusername):
Mon Jun 16 01:01:03 2003:myusername:mypassword:my@old.email:111.222.33 +3.444 Mon Jun 16 01:01:04 2003:myusername2:mypassword2:my@old.email:213.111. +231.444
....and would the code for this search be quicker if the file only contained 'myusername', and no other data?
Cheers Peeps.

Replies are listed 'Best First'.
Re: Quick User Existance Check?
by hardburn (Abbot) on Jun 25, 2003 at 17:28 UTC

    Why the fixation on speed? Worry about how long it takes to implement. Only worry about execution time if it turns out to be a problem later.

    For your second question, you can slurp the entire file into an array and then search the array, which should speed up the IO (which is easily the slowest part). Example:

    open(FH, '<', 'somefile.txt') or die $!; my @in = <FH>; close(FH); my $want_username = 'myusername'; my $hit; while( (! $hit) && (my $entry = shift @in) ) { my $in_user = (split /:/, $entry)[1]; $hit = ($in_user eq $username); }

    Update: Typo in variable name.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      ..also, with the code that hardburn generously provided, how would i put a simple display of 'username exists' or 'username not taken' in there?
Re: Quick User Existance Check?
by waswas-fng (Curate) on Jun 25, 2003 at 18:12 UTC
    Don't know why everyone is so biased aganst posters that ask for a speed tip -- not everyone sits here and trys to pre-optimize every line of code -- as for the posters post how do you know that he does not have a finnished app in which he seems the tight inner loop running too slow for his needs?

    Anyways, if the unix host has a shadowed passeord file most of the time normal users are allowed to read the /etc/passwd file as it has no password entries in it. you can slurp that file before you tight loop and make a hash of usernames then just check if they are defined. This will save you (on most systems getpwnam is not cached ...) the load /etc/passwd, search /etc/passwd steps per user lookup. I had this same problem at a site that had a very large password file where getpwnam was taking 10 seconds to run per call -- it speeded up my tight loop by 20 minutes.

    -Waswas

    Edited: one note with this method, there is a chance for a race condition if the password file is not sorda static -- if a user is added after you make the hash and before your tight loop is done the check with give you a false negitive match or if the user is deleted before the tight loop finishes a false positive.
      This will work if the system is guaranteed to use /etc/passwd, or if it's your system and it does use /etc/passwd, but it's not portable. It won't work if the system uses NIS, LDAP, a database-backed PAM module, etc. A more portable way of doing the same thing is getpwent.

      And with either of these techniques, which is faster is determined by the speed of the backend, the number of users, and how many you're looking up. For example, it's probably not worth reading a 50,000-user remote NIS database to find 50 users, but it may be worth reading a 50,000-user /etc/passwd for 50 users.

      As usual, the best overall answer is try a few things and benchmark.

      The general tone of responses is based on an educated guess of real needs judging from past experience with other people asking those questions.

      As for the past experience with people trying to speed things up, well the following essay on code tuning is exactly accurate. Yes, there are times that you need to tune code. I have been there, and done that. But most of the people who think they need that are just shooting themselves in the foot. What they really need to do is learn to write clearer code, get it working, and then be able to step back and do the really valuable kinds of analysis on the overall project.

      The image that comes to mind is someone who is so focussed on the need to be moving really fast that they are tripping over their own two feet. Get them to focus on effective walking motions, and they get farther immediately, plus are going to be in a better position to learn how to run later...

        I can see your point Tilly, I guess I did not even think about that viewpoint when I posted because I have dealt with the exact same speed issue the person was posting about before. Where a batch check of many names to a silly large /etc/passwd file was taking way to long using getpwnam(). In my instance it changed my average runtime from 14 minutes down to <15 seconds to use my method instead of getpwnam()

        BTW, it is great having you back! I missed your insightful posts while you were kept from us.

        -Waswas
      Hi There, I indeed do have a finished app, but am concerned about how long it is going to take for my script to detect if a user exists on the system when there are 500,000+ users on it.

      On a seperate note, how long would you say that 500,000 lines of usernames in a file would take to search?
        If it is a local password file you will run into about the same issue I described above where the search can take like 10 seconds per name with the std lib getpwnam. building a hash will take about that same amount of time but the time will be preloaded -- meaning getpwnam of 1000 users against a 500,000 user /etc/passwd file you get 1000 x N (N = number of secs to search the file) hash method you get N + (Y x 1000) where Y is the time it takes to lookup a hash entry in perl (not very long)

        -Waswas