2

I'm trying to write a script that accepts group numbers (GID) as parameters. The parameters can be any number. The task of the script is to calculate and display the number of users belonging to the given groups (based on the /etc/passwd file). The script can not use the awk command.

I wrote it for now

#!/bin/bash 
cat /etc/passwd 
test(){
local dir gid name pass shell uid user
while IFS=':' read user pass uid gid name dir shell ;do
}

and I do not know what's next?

  • 1
    Are you only interested in primary groups or should you also count users' supplementary groups? – Kusalananda Jan 7 at 20:47
  • Is this a homework exercise? – RalfFriedl Jan 7 at 21:00
  • 1
    @RalfFriedl I have yet to see a real question that is actually about parsing /etc/passwd for anything other than homework. – Kusalananda Jan 7 at 21:03
2

All groups are in the group database. To count the number of members of a group, extract the members and count the commas in-between them. The number of group members is 1 plus this number.

#!/bin/sh

n=$( getent group "$1" | cut -d : -f 4 | grep -o , | wc -l )

printf 'There are %d members of group %s\n' "$(( n + 1 ))" "$1"

The downside of this approach is that you will always get at least 1 member as output, even if the group is invalid. We can test for a valid group first though:

#!/bin/sh

if ! getent group "$1" >/dev/null; then
    printf 'No such group: %s\n' "$1" >&2
    exit 1
fi

n=$( getent group "$1" | cut -d : -f 4 | grep -o , | wc -l )

printf 'There are %d members of group %s\n' "$(( n + 1 ))" "$1"

The script accept both numeric GIDs and group names as its first command line argument.

With awk, you would instead do

n=$( getent group "$1" | awk -F : '{ print split($4,dummy,",") }' )

and then not add 1 to $n later, or just

getent group "$1" | awk -F : '
    { 
        printf("There are %d members of group %s (%d)\n",
            split($4,dummy,","), $1, $3)
    }'

without the (shell) printf or the n variable.

This counts group memberships as recorded in the group database. To count only primary group memberships, use something like

n=$( getent passwd | cut -d : -f 4 | grep -cxF "$1" )

But again, you may want to check that $1 is indeed a valid group ID first.

To count both primary and supplementary group memberships, it may be best to loop over all users and use id on each:

getent passwd | cut -d : -f 1 |
while read user; do
    if id -G "$user" | tr ' ' '\n' | grep -q -xF "$1"; then
        n=$(( n + 1 ))
    fi
done

This would extract all usernames, then call id -G on each and transform the resulting list of GIDs into a newline-delimited list. The grep then determines whether the given GID is part of that list, and if it is, n is incremented by one.

Or quicker, but uglier,

n=$( getent passwd | cut -d : -f 1 |
     while read user; do
         id -G "$user"
     done | tr ' ' '\n' | grep -c -xF "$1" )

or even,

n=$( getent passwd    | cut -d : -f 1 |
     xargs -n 1 id -G | tr ' ' '\n'   |
     grep -c -xF "$1" )

The reason this may be a good approach is that there may be users whose primary group does not contain themselves in the group database.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.