Splitting Unix command for use with exec [duplicate] Splitting Unix command for use with exec [duplicate] unix unix

Splitting Unix command for use with exec [duplicate]


So your input is a single string, something like:

"/bin/cat file1 file2"

No, you can't just pass "/bin/cat" as one argument to execl, and "file1 file2" as another argument. That would cause /bin/cat to attempt to open a file named file1 file2. You want it to open two files, file1 and file2, which means you need to pass three separate arguments.

execl probably isn't suitable for what you're doing. It's a variadic function; to call it, you have to know when you write your code how many arguments you want to pass to it. So this:

execl("/bin/cat", "file1", "file2");

should work, but you can't build that call from a string.

You want to use one of the execv*() functions instead. For example:

int execv(const char *path, char *const argv[]);

The argv argument is a pointer-to-pointer-to-char, which should point to the first element of an array of char* elements, each of which points to the first character of a '\0'-terminated string.

So you'll have to build that array of pointers, and initialize each one to point to a string argument.

Now if you have an array containing the string:

"/bin/cat file1 file2"

one approach would be to replace the spaces with null characters:

"/bin/cat\0file1\0file2\0"

(that last \0 was already there). You could then construct your array of char* so that each element points either to the beginning of the array, or just after one of the '\0' characters you just created. Each such pointer is a valid pointer to a string.

But I wouldn't necessarily recommend that approach. You're going to run into problems if your input string happens to contain multiple spaces between words (which you'll probably want to treat as single spaces), or if you want to do something fancy like expanding wildcards. I suggest just allocating the arrays yourself and copying the appropriate data into them. The space you save by re-using your input string isn't worth the effort.

Of course the simplest approach is:

char command[] = "/bin/cat file1 file2";system(command);exit(0);

which passes the command string to /bin/sh, which does all that work for you. But then you wouldn't be learning how to use the exec*() functions, which I presume is the point of this exercise.


Yes, you need to pass arguments as separate strings.

For execlX functions you need to pass each argument as an argument:

execl(prog, arg1, arg2,...);

For execvX functions you need to pass an array of c-style strings:

char **argv = /* ... */;argv[0] = "arg1";argv[1] = "arg2";execv(prog, args);

To split the input string you can use strtok, or just do something like:

char **argv = /* malloc stuff */;char *prev = in;cnt = 0;while (in[0]) {  if (in[0] == ' ') {    in[0] = 0;    argv[cnt++] = prev;    prev = in + 1;  }  in++;}argv[cnt++] = prev;argv[cnt]   = NULL;


There are basically two ways to call exec, either provide all arguments one by one (execl) or provide an array of arguments (execv).

If you provide a long string having all arguments separated with \0 exec will not understand that other arguments exist after the first one.

So you have either to

  • use execl and provide a list of arguments, eg (..., in, in+x, in+y, NULL)
  • or make an array of (char *) strings each of the elements pointing to in, in+x, in+y, ..., and use execv

with x and y (...) being the index in the long string of the arguments, e.g. in being

command\0arg1\0arg2\0^0       ^8    ^13

x would be 8 and y would be 13. And you could create an array of strings

char *args[] = { in, in+x, in+y, NULL };

then use execv execv(in, args);