2

I want to write a shell script which will add list of users, defined in users.txt, to multiple existing groups.

For example, I have a, b, c, d, e, f, g users which will be added to the groups according to script, and I have p, q, r, s, t groups. Below is the expected output of /etc/groups file :

p:x:10029:a,c,d
q:x:10030:b,c,f,g
r:x:10031:a,b,c,e
s:x:10032:c,g
t:x:10033:a,b,c,d,e

so how to achieve this ?

  • How do you specify which users go to each group? How is formatted your users.txt input file? – lgeorget Jul 17 '14 at 7:21
  • @lgeorget: It will be fixed. I mean for particular group, users will be predefined. say group p will always have users a, b, f likewise other groups too would have some users. – Rahul Jul 17 '14 at 7:54
  • There are several answers for your questionsyet. The main difference (in my opinion) is whether you specify for each group the users it includes, or for each user, the groups it belongs to. – lgeorget Jul 17 '14 at 11:17
5

The best and simplest approach would be to parse a file with the required information as suggested by @DannyG. While that's the way I would do it myself, another would be to hardcode the user/groups combinations in your script. For example:

#!/usr/bin/env bash

## Set up an indexed array where the user is the key
## and the groups the values.
declare -A groups=(
    ["alice"]="groupA,groupB" 
    ["bob"]="groupA,groupC" 
    ["cathy"]="groupB,groupD"
)

## Now, go through each user (key) of the array,
## create the user and add them to the right groups.
for user in "${!groups[@]}"; do 
    useradd -U -G "${groups[$user]}" "$user" 
done

NOTE: The above assumes a bash version >= 4 since associative arrays were not available in earlier versions.

5

Since no input example is given, I'm going to assume a very basic patern:

Uesrs groups
a p,r,t  
b p,q 

In that case you have several options, because usermod -G can use the second column natively.

something like

while read line
do
    usermod -G "$(cut -f2 -d" ")" $(cut -f1 -d" ")
done < users.txt

The while loop reads each line from users.txt, and passes it to usermod.
the command usermod -G group1,group2,group3 user changes the user's groups to the requested groups.
cut merely separates the fields based on delimiter -d " ", so first field is used as username (login name) and 2nd field is for the groups. I f you wish to append the groups to current (existing) groups - add -a so the command looks like usermod -a -G ...

  • @Dani_I: Thank you for your suggestion.. It helped me in another scripts as well. – Rahul Jul 22 '14 at 1:48
3

Given your comments, you can just statically build the script with the groups hard-written in it. This script expect a list of users, one user per line, on the standard input. So call it with ./script < users.txt for example.

#!/bin/bash

groups="p q r" # the list of all groups you want your users in

# the following function is a case statement
# it takes as first argument a user, and as second argument a group
# it returns 0 if the user must be added to the group and 1 otherwise
must_belong_to() {
     case $2 in  # first we explore all the groups
     p)
          case $1 in  # and for each of them, we examine the users
          a | b )  # first selection: the users that must belong to the group
              true
          ;;
          *) # second selection: all the others
              false
          ;;
          esac
      q)
          # same here...
          ;;
      esac
  }

# we loop on the input file, to process one entry 
# (i.e. one user) at a time
while read user
do
    # We add the user. You may want to give some options here 
    # like home directory (-d), password (-p)...
    useradd $user 

    # then we loop on the existing groups to see in which 
    # one the user must be added
    for g in $groups  
    do
        # if the user must be added to the group $g
        if must_belong_to $user $g  
        then
             # we add it with the command gpasswd
             gpasswd -a $user $g 
        fi
    done
 done

As explained by @terdon, this version of must_belong_to() can grow big quickly. Here is another solution using associative arrays:

#!/bin/bash
declare -A groups

# we declare all the groups and then, for each one, its members
all_the_groups="a b"
groups[a]="p q r"
groups[b]="q r s"

must_belong_to() {
    # we extract a list of all users for the group in parameter
    read -a all_the_users <<< "${groups["$2"]}"

    # we iterate over the users from the group
    for u in $all_the_users
    do
        # if the user belong to the group, 
        # we return here
        [[ $u == $1 ]] && return 0
    done

    # in case the user dosn't belong to the group,
    # we end up here
    return 1
}
  • can you please elaborate this ? As I have mentioned I'm new to shell script. – Rahul Jul 17 '14 at 8:29
  • 1
    @arzyfex Sure, I commented my script. Is it more clear? – lgeorget Jul 17 '14 at 8:36

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.