I want my grep to print a user list from /etc/passwd, and I've studied /etc/login.defs' minmax values for the ones I want my grep to fetch:

# Min/max values for automatic uid selection in useradd
UID_MIN          1000
UID_MAX         60000
# System accounts
#SYS_UID_MIN          100
#SYS_UID_MAX          999

Actual user IDs start at 1000 and finish at 60000, and system user IDs start at 100 and finish at 999.

So I made my script look like this (warning spanish text):

cat /etc/passwd | grep -E "*:[*-6][0-9][0-9][0-9][0-9]:*" | cut -d":" -f1
cat /etc/passwd | grep -E "*:[1-9][0-9][0-9]:*" | cut -d":" -f1 

It's obviously plain not working and grep is very hard for me so I'm not sure how to make it work. I tried (and always try) reading others' solutions but I think I'll need this one explained to me if I ever want to learn.

If possible I'm trying to avoid perl territory. I can't handle that much yet though I understand what it's famed for.

Anything else you need to know to help me, let me know.

Thanks! (also, first post ever here)

  • 2
    much easier to use a language that can do arithmetic comparisons e.g. awk -F: '$3>=1000' /etc/passwd – steeldriver Aug 24 '15 at 19:59
  • @steeldriver I see, never really learned about that one, will investigate. – user442985 Aug 24 '15 at 20:00

This awk command does what you want. First, you set the record separator to : with FS=":", check if the third element is 1000-60000, and if so, print element 1 (username):

awk 'FS=":" {if ($3 > 999 && $3 < 60001) print $1}' < /etc/passwd
  • ...and fwiw, here's a Perl one-liner that does the same thing: perl -Mstrict -nE 'my @a=split /:/; if ($a[2] > 999 && $a[2] < 60001){ say $a[0]; }' /etc/passwd – stevieb Aug 24 '15 at 21:14

Another awk version, with arrays. A bit more lengthy but working

awk -F':' ' $3 >= 1000 && $1 != "nobody" {i++;humanuser[i]=$1 } $3 < 999 { k++;sysuser[k]=$1} END {printf"****HUMAN USERS\n";for (j=1;j<=i;j++) printf humanuser[j]" "; printf "\n*****SYSTEM USERS\n"; for(m=1;m<=k;m++) printf sysuser[m]" "}' /etc/passwd

Sample output:

xieerqi testuser 
root daemon bin sys sync games man lp mail news uucp proxy www-data backup list irc gnats libuuid syslog messagebus usbmux dnsmasq avahi-autoipd kernoops rtkit saned whoopsie speech-dispatcher avahi lightdm colord hplip pulse gdm 
  • You could use UID_MIN=$(awk '/^#*UID_MIN/ {print $2}' /etc/login.defs); SYS_UID_MAX=$(awk '/^#*SYS_UID_MAX/ {print $2}' /etc/login.defs); awk -F':' ' $3 >= '"$UID_MIN"' && $1 != "nobody" {i++;humanuser[i]=$1 } $3 < '"$SYS_UID_MAX"' { k++;sysuser[k]=$1} END {printf"****HUMAN USERS\n";for (j=1;j<=i;j++) printf humanuser[j]" "; printf "\n*****SYSTEM USERS\n"; for(m=1;m<=k;m++) printf sysuser[m]" "}' /etc/passwd – A.B. Aug 25 '15 at 6:03

You can use grep with Perl Compatible RegEx (PCRE) :

  • To get the usernames with UID >= 1000 :

    grep -Po '^[^:]+(?=:[^:]+:\d{4,})' /etc/passwd
  • To get the usernames with 100 <= UID <= 999 :

    grep -Po '^[^:]+(?=:[^:]+:\d{3})' /etc/passwd

Here -P indicates PCRE, -o indicates we are going to take only the matched portion.

  • ^[^:]+ gets us the username, everything upto first :

  • (?=) is zero width positive lookahead pattern, we are using this to ensure that we match our desired portion after the username

  • :[^:]+: matches :x: and then \d{4,} matches four or more digits (>=1000)

  • On the other hand :[^:]+: matched :x: then \d{3} matches exactly three digits (100 to 999).


DISCLAMER: The following java answer is for educational purposes and the fun of coding only. If you downvote, explain in the comments why.


The code bellow reads each line from /etc/passwd , splits that line into strings with : as separator, and sorts users depending on their UID into appropriate ArrayLists.

package com.askubuntu.users.serg;

import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Scanner;

 * A program to sort human and system users from /etc/password
 * @author Serg Kolo
public class UserList {
    private static final String SEPARATOR = "=============";
    private static final int SYS_UID_MAX = 999;
    private static final int UID_MAX = 1000;
    private static final String FILENAME_PASSWD = "/etc/passwd";
    private static final String COLON = ":";
    private static final String NOBODY = "nobody";

     * @param args
     * @throws IOException
    public static void main(String[] args) {
        File f = new File(FILENAME_PASSWD);
        try (Scanner readFile = new Scanner(f)) {
            ArrayList<String> humanUsers = new ArrayList<>();
            ArrayList<String> systemUser = new ArrayList<>();

            while (readFile.hasNext()) {
                String[] field = readFile.nextLine().split(COLON);
                int uid = Integer.parseInt(field[2]);

                if (uid >= UID_MAX && (!NOBODY.equals(field[0]))) {
                } else if (uid <= SYS_UID_MAX) {
            printUsers(humanUsers, "Human Users:");
            printUsers(systemUser, "System Users:");
        } catch (FileNotFoundException e) {

     * print users
     * @param users
     * @param header
    private static void printUsers(ArrayList<String> users, String header) {


  1. Save the code above as userlist.java
  2. Compile and run with your preferred Java IDE. If you prefer command line, do

    javac UserList.java && java UserList
  3. Output will appear in the console of your IDE

Sample output

Human Users:
[xieerqi, testuser]
System Users:
[root, daemon, bin, sys, sync, games, man, lp, mail, news, uucp, proxy, www-data, backup, list, irc, gnats, libuuid, syslog, messagebus, usbmux, dnsmasq, avahi-autoipd, kernoops, rtkit, saned, whoopsie, speech-dispatcher, avahi, lightdm, colord, hplip, pulse, gdm, sshd]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy