I'm trying to loop through 2 groups on macOS and remove users in the admin group if they don't exist in another group.
newadmins=$(dscl . -read Groups/newadmin GroupMembership | cut -c 18-)
adminUsers=$(dscl . -read Groups/admin GroupMembership | cut -c 18-)
for (user in $adminUsers && ! user in $newadmins)
do
dseditgroup -o edit -d $user -t user admin
if [ $? = 0 ]; then echo "Removed user $user from admin group"; fi
else
echo "Admin user $user left alone"
fi
done
The above didn't work. I think I'm confusing shell with other languages. Any help would be appreciated. Thank!
The below script worked exactly as expected:
NEW_ADMIN_USERS=$(dscl . -read Groups/newadmin GroupMembership | cut -d ' ' -f 2-)
ADMIN_USERS=$(dscl . -read Groups/admin GroupMembership | cut -d ' ' -f 2-)
DEFUNCT_ADMIN_USERS=$(grep -vxFf <(echo ${NEW_ADMIN_USERS} | tr ' ' '\n') <(echo ${ADMIN_USERS} | tr ' ' '\n'))
for DEFUNCT_ADMIN_USER in ${DEFUNCT_ADMIN_USERS}
do
if dseditgroup -o edit -d ${defunct_admin_user} -t user admin
then
echo "Removed user ${DEFUNCT_ADMIN_USER} from admin group"
else
echo "Admin user ${DEFUNCT_ADMIN_USER} left alone"
fi
done
Thanks @msbit for all the help!
CodePudding user response:
I would consider doing something like this:
#!/usr/bin/env bash
set -eu
NEW_ADMIN_USERS=$(dscl . -read Groups/newadmin GroupMembership | cut -d ' ' -f 2-)
ADMIN_USERS=$(dscl . -read Groups/admin GroupMembership | cut -d ' ' -f 2-)
DEFUNCT_ADMIN_USERS=$(grep -vxFf <(echo ${NEW_ADMIN_USERS} | tr ' ' '\n') <(echo ${ADMIN_USERS} | tr ' ' '\n'))
for DEFUNCT_ADMIN_USER in ${DEFUNCT_ADMIN_USERS}
do
if dseditgroup -o edit -d ${DEFUNCT_ADMIN_USER} -t user admin
then
echo "Removed user ${DEFUNCT_ADMIN_USER} from admin group"
else
echo "Admin user ${DEFUNCT_ADMIN_USER} left alone"
fi
done
The main thrust of this is using the grep
command put forward by @Jetchisel with process substitution (<()
) to prepare a list of admin users in the ADMIN_USERS
variable but not in the NEW_ADMIN_USERS
variable, then iterating over that variable.
This departs from your approach in a number of ways:
- setting the
errexit
andnounset
options which will cause the script to exit on any error code from a command, including use of unset variables (set -eu
) - using the
field
argument ofcut
with delimiter set to space when parsing the output ofdscl
(cut -d ' ' -f 2-
) - subsequently splitting the list of users into lines with
tr
(tr ' ' '\n'
) - passing the list through to
for
as appropriate (using(
was a syntax error, as I suspect the use of!
would be) - evaluating the return code of
dseditgroup
directly as that is whatif
is testing for - removing the trailing
fi
for the firstif
command, as it's not needed when you have theelse
(and would cause a syntax error due to an apparent floatingelse
)
Please test thoroughly, preferably with a dummy command instead of dseditgroup
before you're 100% happy that this works as expected, and consider setting the xtrace
option (set -x
which will echo all the commands as they are executed), while developing.