Interesting Shell Script Problem [Solved]

I spent yesterday writing (Bash) shell scripts like some kind of machine. I came upon this problem:

function create {
        $HTPASSWD $USERFILE $user $pass
        if [ ! `grep -q " $user " $GROUPFILE` ]; then
                echo "Adding user to group $GROUP ..."
                sed "s/$GROUP\:/$GROUP\: $user/" $GROUPFILE > $GROUPFILE.tmp
                cp $GROUPFILE.tmp $GROUPFILE
        else
                echo "User is already in group $GROUP"
        fi
}

What this should do is add a string to a file if the string is not already in the file. Simple enough but the logic in the ‘if’ is always evaluating to true. If I run the same grep on the command-line and check the return value I get the desired result:

cliph@clflood-desktop:~/bin$ grep -q hello xtranetgroups; echo $?
0
cliph@clflood-desktop:~/bin$ grep -q antihello xtranetgroups; echo $?
1

So then I tried this small piece of code to test command substitution and return codes in if statements (being in a function doesn’t seem to cause a problem):

if [ `ls ./$file` ]; then
	echo "True"
else
	echo "False"
fi

It works perfectly:

cliph@clflood-desktop:~/bin$ ./true file
True
cliph@clflood-desktop:~/bin$ ./true filenothere
ls: ./filenothere: No such file or directory
False

So that leaves me stumped, why does my grep not work in the first example?

11 Responses to “Interesting Shell Script Problem [Solved]”


  1. 1 John Keyes

    Is it because $user evaluates to an empty string?

  2. 2 Cliph

    $user always has a value, the “create” function wont be reached if $user is null

  3. 3 DoC

    In the script, you’re doing this:

    grep -q \” $user \” $GROUPFILE

    On the command line, you’re grepping just for the user. Do you mean to grep for $user with a space on either side? That’s what you’re doing in the script.

  4. 4 Cliph

    Yes, thats what I want to do in case there’s a new user that has a name similar to an old one. grep’s ‘-w’ flag has been pointed out to me and should work just as well as whitespace padding but I’m getting the same result.

  5. 5 DoC

    On the other hand, I don’t think that grep will actually return a 1 or 0 in your script. backticks return the output from a statement, not the return value. So, you’re NOTing nothing (i.e. 0) which evaluates to true.

    Do the grep in a statement before your if, then use the if to test the value of $?

    grep -w $user $GROUPFILE
    if [ ! $? == “1″]
    etc

  6. 6 johnke

    if grep -vq ” $user ” $GROUPFILE
    then

    … seems to work for me (ubuntu hoary).

  7. 7 Cliph

    DoC wins for the first working solution and an explaination.

    Learning is fun.

  8. 8 johnke

    Surely I should get some points for elegance and lack of disruption to your original script? :(

  9. 9 Cliph

    I tried yours and it didn’t work, for me at least. Good effort though.

    Thanks to everyone who replied.

  10. 10 DoC

    I win! \o/

Leave a Reply