Q: exec() any command in C Say in C, I want to call execvp() on any string command.  Command can just be:
char command[] = "ls -l";
char command[] = "rm *.txt";
char command[] = "cat makefile";

I want to put this command variable inside execvp().  So the exec() flavored function can just run with any kind of arbitrary command.
How can I do that?  Thanks.
NOTE: system() is not allowed.

A: No, the exec family of functions does not take a single string command line like system does. Instead it uses an argv-like array of strings:
char *command = "/path/to/command";
char *arguments[] = { "command", "first argument", "second argument", NULL };
execvp(command, arguments);

Note that the first entry in the arguments array is the command itself, and that the array is terminated by NULL.
Did you check the manual page?

A: To use any of the execve-style functions, you'll need to parse the command line yourself and build an argv vector. The functions take a char**, where the last element is null - you'll need to allocate enough memory for all this. Then your execve-style call should work.
(p.s. You haven't mentioned anything about fork...)

A: If you have to call execvp(), then you will need to split up those strings into an executable name and an array of arguments (the first being the "name" of the program and the last being a NULL pointer).
That means something like:
char cmd1[] = "ls";  char *args1[] = {"ls", "-l", NULL};
char cmd1[] = "rm";  char *args1[] = {"rm", "*.txt", NULL}; // but see
                                                            // globbing below.
char cmd1[] = "cat"; char *args1[] = {"cat", "makefile", NULL};

This is a non-trivial exercise, especially if you want to allow for quoting, globbing, escaping and so forth.
Quoting means you'll have to be careful with commands like:
rm "file with spaces.txt"

in that you can't simply break on the spaces - you'll have to interpret items in the command much the same as the shell does. Simplistic breaking on spaces would give you a command with three arguments for that string above, rather than the correct one.
By globbing, I mean you'll almost certainly have problems with something like *.txt since it's typically the shell which expands these arguments. Passing that directly to execvp() will result in a single argument of literally *.txt rather than many arguments matching all the text files in your current directory.
Quoting means that you'll have to handle things like:
ls -l "file with spaces and \" quote in it"

which will further complicate your parser.
Don't get me wrong, it can be done, but it's probably a damn sight easier just using system().
If you're still thinking of going the execvp() route, you'll have to:


*

*split the string into separate tokens (rather hard, since you have to handle quotes and escapes).

*glob all the arguments, meaning that those with wildcards in them (and only ones that aren't escaped or protected by virtue of being inside quotes) are expanded into multiple arguments.

*construct the argument array, with the command at the front and a NULL at the end.

*call execvp() with the parameters being first element in that array and the address of the array.


A: In order to have things like "*" ">", "<", "&" etc. to work, you need to execute "/bin/sh" and pass in your command line as arguments. So, it comes down to tokenizing your string.

A: What you need to do here is make the shell parse the command. So consider this:
/bin/sh -c 'rm *.txt'

That should get you going in the right direction. :)
