3

I'm writing a bash script wherein I want to check that one of the arguments passed to it is a valid group.

I have the line

if [ `grep -c -e '\b$2\b' /etc/group` -eq 0 ]; then
  echo "Error: $2 is not a valid group."
else

Which always tells me that valid groups aren't valid.

I think it's an escaping problem; I think it's grepping for a group called $2. The error message properly shows the passed argument. However I'm not sure if I'm escaping $2 within the backticks properly.

How do I get this line working?

  • Try using double-quotes instead. I think the shell is not expanding the $2 parameter right with single quotes. – user13742 Jan 6 '12 at 15:12
7

Using grep's -q option is much more efficient than command substitution.

if ! grep -q -e "^$2:" /etc/group; then
    echo "Error: $2 not a valid group" >&2
fi

The issue is single quotes (') prevent shell variable expansion ($). You need to use double quotes (").

  • 1
    +1, beat me by 10 seconds. In short, grep will return 0 (success) if it finds a match, so there's no reason to count the matches. – l0b0 Jan 6 '12 at 15:17
  • Check out Gilles' answer for much more detailed explanations. – jw013 Jan 8 '12 at 19:44
2
grep -q -e "^$2:" /etc/group

should work.

(single quotes prevent interpolation)

1

You're passing \b$2\b to grep literally because of the single quotes. To allow $2 to expand to the value of the argument, use "$2". Also, quoting between backquotes can get tricky; use $(…), which has the same meaning as `…` (command substitution) but behaves sanely with regards to quoting.

if [ $(grep -c -e "\b$2\b" /etc/group) -eq 0 ]; then …

Next, counting the matches is overly complicated: you can use grep's return status to know whether there were matches. Pass the -q option to tell grep that you aren't interested in any output, just the return status.

if ! grep -q -e "\b$2\b" /etc/group; then …

Next, your search is wrong. You're looking for the word $2, but that could match a user name, or a part of a group name that contains a punctuation character, or a few more exotic mismatches. The group name is the first colon-delimited field, so search for that.

if ! grep -q -e "^$2:" /etc/group; then …

Note that you may need to sanitize the input: $2 must not contain any character that's special to grep or that's a group delimiter.

case $2 in
  *[][\.*^$]*) echo "Unsupported character in the group name";;
esac
if ! grep -q -e "^$2:" /etc/group; then …

Finally, grep /etc/group is not the right tool here, if you can avoid it. You can only find local group names that way, not groups coming from NIS or LDAP or unusual setups. Most modern unices (at least Solaris, Linux and *BSD) have a getent command to retrieve entries from system databases including the group database.

if ! getent group "$2" >/dev/null; then …

(For users, instead of looking in /etc/passwd, use getent passwd, or more portably call id.)

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.