Splitting Unix command for use with exec [重复]

问题描述 投票:0回答:3

我有一个程序,它从输入中获取命令,然后使用

execl
执行它(它必须是
execvp
系列的功能)。现在,假设输入行是
in
,我可以简单地使用
execl(allBeforeFirstSpaceFromIn, in);
,还是必须将
in
分成更小的字符串?如果是这样,我可以简单地将所有空格更改为
\0
吗?

c unix exec ansi-c
3个回答
5
投票

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

"/bin/cat file1 file2"

不,您不能只将

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

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

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

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

您想改用

execv*()
功能之一。例如:

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

argv
参数是一个指向字符的指针,它应该指向
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*()
功能,我认为这是本练习的重点。


2
投票

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

对于

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;

1
投票

基本上有两种调用exec的方法,要么一个一个地提供所有参数(execl),要么提供一个参数数组(execv)。

如果你提供一个长字符串,所有参数都用

\0
exec 将无法理解在第一个参数之后存在其他参数。

所以你必须

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

其中

x
y
(...) 是参数长字符串中的索引,例如
in
存在

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

x
将是 8,
y
将是 13。您可以创建一个字符串数组

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

然后使用execv

execv(in, args);

© www.soinside.com 2019 - 2024. All rights reserved.