拆分Unix命令以与exec一起使用

时间:2013-03-30 00:41:59

标签: c unix exec ansi

我有一个程序从输入中获取命令,然后使用execl执行它(它必须是来自execvp系列的函数)。现在,假设输入行是in,我可以简单地使用execl(allBeforeFirstSpaceFromIn, in);,还是必须将in分成更小的字符串?如果是这样,我可以简单地将所有空格更改为\0吗?

3 个答案:

答案 0 :(得分:4)

所以你的输入是一个单独的字符串,如:

"/bin/cat file1 file2"

不,您不能将"/bin/cat"作为一个参数传递给execl,而"file1 file2"作为另一个参数传递。这会导致/bin/cat尝试打开名为file1 file2的文件。您希望它打开两个文件file1file2,这意味着您需要传递三个单独的参数。

execl可能不适合您正在做的事情。它是一种可变函数;要调用它,您必须在编写代码时知道 要传递给它的参数数量。所以这个:

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

应该可以工作,但你不能从字符串构建该调用。

您想要使用其中一个execv*()功能。例如:

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

argv参数是一个指向char的指针,它应该指向char*元素数组的第一个元素,每个元素指向一个元素的第一个字符。 '\0' - 终止字符串。

所以你必须构建那个指针数组,并初始化每个指针指向一个字符串参数。

现在,如果你有一个包含字符串的数组:

"/bin/cat file1 file2"

一种方法是用空字符替换空格:

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

(最后\0已经存在)。然后,您可以构造char*数组,以便每个元素指向数组的开头,或者仅指向您刚刚创建的'\0'个字符之一。每个这样的指针都是指向字符串的有效指针。

但我不一定会推荐这种方法。如果您的输入字符串恰好在单词之间包含多个空格(您可能希望将其视为单个空格),或者您想要做一些像扩展通配符这样的事情,那么您将遇到问题。我建议你自己分配数组并将适当的数据复制到它们中。通过重新使用输入字符串节省的空间是不值得的。

当然最简单的方法是:

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

将命令字符串传递给/bin/sh,它可以完成所有工作。但是你不会学习如何使用exec*()函数,我认为这是本练习的重点。

答案 1 :(得分:1)

是的,您需要将参数作为单独的字符串传递。

对于execlX函数,您需要将每个参数作为参数传递:

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

对于execvX函数,您需要传递一组c风格的字符串:

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

要分割输入字符串,您可以使用strtok,或者只执行以下操作:

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;

答案 2 :(得分:1)

基本上有两种方法可以调用 exec ,或者逐个提供所有参数( execl )或者提供一个参数数组( execv )。

如果你提供一个长字符串,所有参数都以\0 分隔,那么 将不会理解在第一个参数之后存在其他参数。

所以你要么

  • 使用 execl 并提供参数列表,例如(...,in,in + x,in + y,NULL)
  • 或制作一个(char *)字符串数组,每个元素指向inin+xin+y,...,并使用 execv

xy(...)是参数的长字符串中的索引,例如in正在

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

x为8,y为13.你可以创建一个字符串数组

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

然后使用 execv execv(in, args);