Modifying correct group name and ID within /etc/group file

1.4k views Asked by At

I am passing 2 parms to a bash script. The first parm is group and the second parm is the groupID. I want to write a bash script that will check if group is present in /etc/group or not. If not present, then the script should add group and gid to /etc/group. If present then it should match the gid with the 2nd param. If gid doesn't match the 2nd param then it should overwrite the gid with 2nd parm.

In short, group name and gid that I am passing to the script, should be in the /etc/group file.

I am running the command as:

./addgroup.sh groupa 123

suppose /etc/group has an entry:

groupa:x:345

After the running the command, when i browse /etc/group it should have value

groupa:x:123

I have written the following addgroup.sh so far:

if grep -q "^$1:" /etc/group
then
    echo "group $1 exists:SUCCESS"
else
    grep -q "^$1:" /etc/group || /bin/echo "$1:x:$2:" >> /etc/group
    cat /etc/group
    echo "group $1 added:SUCCESS"
fi
2

There are 2 answers

4
John1024 On

I believe that this code meets your needs and is simpler:

{ grep -v "^$1:" /etc/group; echo "$1:x:$2:"; } >/etc/group.tmp && mv /etc/group.tmp /etc/group

The question states that you would like to update the group ID even if the group already exists. The code here has that feature.

How it works:

  • grep -v "^$1:" /etc/group

    This removes the existing definition of group $1 if one exists.

  • echo "$1:x:$2:"

    This adds back a correct definition of group $1 with the correct group ID.

  • { ... } && mv /etc/group.tmp /etc/group

    If commands in braces executed successfully, this updates /etc/group.

Preserving existing group members

As sjnarv points out, one might want to preserve existing group members. In that case:

awk -v g="$1" -v id="$2" -F: -i inplace '$1 == g{save=$4; next} {print} ENDFILE{print g, "x", id, save}' OFS=: /etc/group

This requires GNU awk. (On Ubuntu, GNU awk is available but it is not usually the default.) For standard awk:

awk -v g="$1" -v id="$2" -F: '$1 == g{save=$4; next} {print} END{print g, "x", id, save}' OFS=: /etc/group > /etc/group.tmp && mv /etc/group.tmp /etc/group

How it works:

  • -v g="$1" -v id="$2"

    This uses shell variables $1 and $2 to define two awk variables g and id.

  • -F:

    This tells awk that our field separator is :.

  • -i inplace

    This tells awk to modify the file in-place (GNU awk only).

  • $1 == g{save=$4; next}

    If we encounter an existing definition of group g in the file, save the group members (the fourth field) in variable save and then skip the rest of the commands and jump to the next line.

    Here, inside the awk script, $1 and $4 are awk variables representing the first and fourth fields on the line. These variables are entirely separate and unrelated to the shell variables $ and $4 which would represent arguments to the shell script.

  • print

    For all other lines in /etc/group, we just print them as is.

  • ENDFILE{print g, "x", id, save}

    After reaching the end of /etc/group, we print the new definition of group g with group ID id and group members save. (For standard awk, we use END in place of ENDFILE.)

  • OFS=:

    This tells awk to use : as the field separator on output.

5
sjnarv On

@John1024 has a nice answer for manual editing of the text file /etc/group, although I suspect it may have an issue not damaging a group that has members:

docker:x:1001:bob,alice

Also, most current systems have a pair of group-related files: /etc/group and /etc/gshadow.

If the task at hand is a real sysadmin one, consider using the tools already in place for managing the groups-related files: groupadd and groupmod.

Here's an attempt:

#!/usr/bin/env bash

if [[ $# -ne 2 ]]; then
  echo "Usage: $(basename $0) <groupname> <groupid>" 1>&2
  exit 1
fi

set -e

[[ $EUID -eq 0 ]] || exec sudo "$0" "$@"

type groupadd &> /dev/null || PATH=/sbin:/usr/sbin:"$PATH"

# Add the group if it's not already present
#
grep -q "^$1:" /etc/group || groupadd -g "$2" "$1"

# Edit the group if it does not have the desired gid
# (See groupmod(8) for implications of a gid change here -
#  note that it will *not* change files' group ownerships
#  out in the system.)
#
grep -q "^$1:[^:]*:$2:" /etc/group || groupmod -g "$2" "$1"

Edit: a simpler version with no check for running as root or attempt to use sudo, and a simpler interpreter line that assumes bash is available on /bin/bash on the system.

#!/bin/bash

if [[ $# -ne 2 ]]; then
  echo "Usage: $(basename $0) <groupname> <groupid>" 1>&2
  exit 1
fi

set -e

grep -q "^$1:" /etc/group || groupadd -g "$2" "$1"
grep -q "^$1:[^:]*:$2:" /etc/group || groupmod -g "$2" "$1"

If saved as groupedit.sh and made executable, run as root directly or via

$ sudo ./groupedit.sh

The groupadd/groupmod commands are the same, just without the comments of the first version.