Search code examples
cgrepexecexecvp

How to use execvp() with grep?


I am trying to exec() a call to grep inside of my C program. I am looking for the number of occurrences of a string pattern in a given file, which can be achieved with:

$ grep -e my_string -F my_file.txt -c

Which gives a number output as expected, such as:

5

However, what I hoped would be equivalent seems to be having some difficulties. The following code:

char *arg_list[] = {"-e", "my_string", "-F", "my_file.txt", "-c", "\0"};

int pid;
if ((pid = fork()) == 0) {
    if (execvp("grep", arg_list) < 0)
        perror("execvp");
}

Results in:

 my_file.txt:5
 -e: : No such file or directory

There are two issues. First, I just want the number-- not the file in which it is found. Second, I'm not sure why it is trying to assert that the -e flag needs to be a file. If I switch around the argument list to be:

char *arg_list[] = {"-F", "my_file.txt", "-e", "my_string", "-c", "\0"};

Then I get back:

my_file.txt:5
-F: : No such file or directory

I'm not sure where to start looking for why this is happening. I'm also not sure why the output of the grep call from the command-line is just a number, but the exec()'d grep call outputs both the filename and number.

Any help would be appreciated! Thank you.

EDIT:

Solution: include the program name in the argument list, or simply use the system() call. Also, RTFM.


Solution

  • You have two problems (insert JWZ quote about regular expressions here):

    1. The first argument in the array passed exec gets passed in as argv[0] to the new executable. Ordinarily, this is the name of the executable, and it's what programs use to figure out their own name. So you're telling grep that its name is -e, and its arguments are my_string -F my_file.txt -c "". It's not getting the -e argument like you might expect, so it misinterprets its arguments and gives you an error.

    2. You're not properly NULL-terminating the array of arguments to exec. The last argument must be a literal NULL, not a string "\0". That string is an empty string, but it's not a null pointer.