Reputation: 10882
I put this together, but it sucks: (e.g. magic numbers in there, text parsing.. boo!)
awk -F: '{if($3 >= 1000 && $3 < 2**16-2) print $1}' /etc/passwd
What's the proper way to do this?
Upvotes: 9
Views: 10453
Reputation: 189317
Here's a simplification of @StephenOstermiller's answer which gets it done with only two processes. I think it is easier to read, too (provided you are familiar with the awk NR==FNR
idiom).
getent passwd |
awk 'NR==FNR { if ($1 ~ /^UID_(MIN|MAX)$/) m[$1] = $2; next }
{ split ($0, a, /:/);
if (a[3] >= m["UID_MIN"] && a[3] <= m["UID_MAX"] && a[7] !~ /(false|nologin)$/)
print a[1] }' /etc/login.defs -
The different split patterns in the two inputs is a bit of a wart; maybe you could fix that more elegantly somehow.
Upvotes: 1
Reputation: 4363
Here's another approach that only spawns one external program, getent
(suggested by @AnsgarWiechers) so that both local and networked passwd databases will be used. This one reduces the number of forks to just one for getent
itself. Its portability is limited somewhat by requiring bash4, however.
get_users ()
{
local IFS=$' \t#'
while read var val ; do
case "$var" in
UID_MIN) min="$val" ;;
UID_MAX) max="$val" ;;
esac
done < /etc/login.defs
declare -A users
local IFS=:
while read user pass uid gid gecos home shell; do
if (( min <= uid && uid <= max )) && [[ ! $shell =~ '/(nologin|false)$' ]]; then
users[$user]=1
fi
done < <(getent passwd 2>/dev/null)
echo ${!users[@]}
}
Upvotes: 2
Reputation: 200203
Extract the minimum and maximum user IDs from /etc/login.defs
and then select the users with IDs between these margins from /etc/passwd
:
UID_MIN=$(awk '/^UID_MIN/ {print $2}' /etc/login.defs)
UID_MAX=$(awk '/^UID_MAX/ {print $2}' /etc/login.defs)
awk -F: -v min=$UID_MIN -v max=$UID_MAX '$3 >= min && $3 <= max{print $1}' /etc/passwd
Upvotes: 2
Reputation: 25504
Some unix systems don't use /etc/passwd
, or have users that are not specified there. You should use getent passwd
instead of reading /etc/passwd
.
My system also has users that are disabled and can lo longer login with their login command set to /bin/false
or /usr/sbin/nologin
. You probably want to exclude them as well.
Here is what works for me including arheops awk command and ansgar's code to get the min and max from login.defs
:
getent passwd | \
grep -vE '(nologin|false)$' | \
awk -F: -v min=`awk '/^UID_MIN/ {print $2}' /etc/login.defs` \
-v max=`awk '/^UID_MAX/ {print $2}' /etc/login.defs` \
'{if(($3 >= min)&&($3 <= max)) print $1}' | \
sort -u
Upvotes: 13
Reputation: 15247
I am unsure why you do only > 1000, beacuase on redhat system it start from 500.
For me this awk script work ok:
awk -F: '{if(($3 >= 500)&&($3 <65534)) print $1}' /etc/passwd
Only uses with passwords:
awk -F: '{if(!(( $2 == "!!")||($2 == "*"))) print $1}' /etc/shadow
Upvotes: 2
Reputation: 6203
So you're just trying to get a list of all users from /etc/passwd? If so, I believe this would be an easier solution:
cut -d":" -f1 /etc/passwd
Edit:
In case you only want a list of user-defined users (not the system users), you can use one of these:
grep -E ":[0-9]{4,6}:[0-9]{4,6}:" /etc/passwd | cut -d: -f1
^ This assumes your system uses 1000 and up for UID and GID for user-defined users
grep /home /etc/passwd | cut -d: -f1
^ This assumes every user-defined user has a home directory.
Other solutions depend on more detailed criteria and your system settings.
Upvotes: 1