Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Is there an easy way to get a list of users who are in all specified groups?

For example, if I have the following users:

fred - rainbow, dell
jane - hp
zippy - rainbow, hp, dell
george - hp, dell
bungle - rainbow, hp, dell

I would like something like this:

[me@box ~]$ magic "dell,hp"
zippy, george, bungle

ie returning the users who are in both dell and hp.

If it is multiple steps that is fine, though if it's not really possible without having to resort to lots of Bash black magic, and it is quicker to do it in a RE-enabled text editor that is also fine.

I'm running on RHEL4 if that makes any difference.

share|improve this question
add comment

4 Answers

up vote 3 down vote accepted

I don't known any tool doing this but it is easy to script.

At first get the list of the users on the system, then run groups on each and at the end, grep on the desired groups :

getent passwd | sed 's/:.*$//g' | \
    while read user; do groups $user; done | \
    grep group1 | grep group2
share|improve this answer
add comment

This works for two groups at a time:

getent group dell hp | cut -d: -f 4 | tr , '\n' | sort | uniq -d | sed ':a;$s/\n/, /g;N;ba'

Put it in a function with some modifications and it will handle any number of groups:

grmagic () {
    getent group "$@" | 
        cut -d: -f 4 | 
        tr , '\n' | 
        sort | 
        uniq -dc | 
        grep "^[[:blank:]]*$#" |
        awk '{all = all d $3; d = ", "} END {print all}'
}

Run it:

$ grmagic dell hp
zippy, george, bungle
$ grmagic dell hp rainbow
zippy, bungle

A function consisting mostly of an AWK script:

grmagic () {
    getent group "$@" |
    awk -F: -v "c=$#" '{
            split($4, a, ","); 
            for (i in a) n[a[i]]++
        } 
        END { 
            for (i in n) 
            if (n[i] == c) {
                printf d i; d=", "
            }; 
            printf "\n"  }'
}
share|improve this answer
add comment

Small python script:

#!/usr/bin/python

import subprocess,sys

group={}

for user in sys.argv[1:]:
    group[user] = set(subprocess.Popen("id -nG %s"%user, stdout=subprocess.PIPE, shell=True).stdout.read().split())

for g in group[sys.argv[1]] & group[sys.argv[2]]:
    print g

Test:

# id user1
uid=1001(user1) gid=1001(user1) groups=1001(user1),1004(us1),1005(dell)
# id user2
uid=1002(user2) gid=1002(user2) groups=1002(user2),1004(us1),1005(dell)
# ./test.py user1 user2
dell
us1
share|improve this answer
add comment

A bash solution that takes more than 1 user per line and print only unique groups. Normal output is one grop per line, use -c to get the output separated by commas.

#!/bin/bash
\unalias -a

if [ $# -lt 1 ]
then
    echo "Need at least one user" 1>&2
fi

RESULT=''
COMMA=0
while [ $# -gt 0 ]
do
    if [ $1 == '-c' ]
    then
        COMMA=1
    else
        RESULT="$RESULT $(id -Gn $1)"
    fi
    shift
done
if [ $COMMA -eq 0 ]
then
    echo $RESULT |tr ' ' '\n'| sort -u
else
    echo $RESULT |tr ' ' '\n' | sort -u |tr '\n' ', ' |sed 's/.$//g'
    echo
fi

Example output:

# ./magic.sh coredump mongodb
audio
cdrom
coredump
dialout
floppy
lpadmin
mongodb
netdev
nogroup
plugdev
powerdev
video

Using -c:

# ./magic.sh -c coredump mongodb
audio,cdrom,coredump,dialout,floppy,lpadmin,mongodb,netdev,nogroup,plugdev,powerdev,video
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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