在我的程序中,我正在执行给定的命令并获得结果(日志和退出状态)。此外,我的程序必须支持特定于shell的命令(即包含shell特定字符〜(tild),|(管道),*)的命令。但是当我尝试通过我的程序在我的主目录中运行sh -c ls | wc
时,它失败并且其退出状态为32512,同时在stderr流"sh: ls | wc: command not found"
中也被打印出来。
但有趣的是,如果我在shell中运行它,命令sh -c ls | wc
的工作正常。
有什么问题?或者更可取的是如何通过我的程序运行shell特定命令(即哪个命令应该运行哪个参数)?
下面的代码部分是fork()之后的子部分。它执行命令。
tokenized_command
是std::vector<std::string>
我的情况"sh", "-c", "ls", "|", "wc"
存储在哪里,我也试图存储"sh", "-c", "\"ls | wc\""
,但结果是一样的。 command
是char *
,其中存储了完整的命令行。
boost::shared_array<const char *> bargv(new const char *[tokenized_command.size() + 1]);
const char **argv = bargv.get();
for(int i = 0; i < tokenized_command.size(); ++i)
{
argv[i] = tokenized_command[i].c_str();
printf("argv[%d]: %s\n", i, argv[i]); //trace
}
argv[tokenized_command.size()] = NULL;
if(execvp(argv[0], (char * const *)argv) == -1)
{
fprintf(stderr, "Failed to execute command %s: %s", command, strerror(errno));
_exit(EXIT_FAILURE);
}
P.S。
我知道使用system(command)
代替execvp
可以解决我的问题。但system()
等待命令完成,这对我的程序来说还不够好。而且我确信在system()
的实现中使用了一个exec-family函数,因此问题也可以通过exec
来解决,但我不知道如何。
答案 0 :(得分:24)
execvp
获取可执行文件的路径,以及用于启动该可执行文件的参数。它不需要bourne shell命令。
ls | wc
是一个bourne shell命令(以及其他命令),由于使用了管道,它不能分解为可执行文件的路径和一些参数。这意味着无法使用execvp
执行此操作。
要使用execvp
执行bourne shell命令,必须执行sh
并传递-c
和参数命令。
因此,您希望使用ls | wc
执行execvp
。
char *const argv[] = {
"sh",
"-c", "ls | wc", // Command to execute.
NULL
};
execvp(argv[0], argv)
你显然已经尝试了
char *const argv[] = {
"sh",
"-c", "ls", // Command to execute.
"|", // Stored in called sh's $0.
"wc", // Stored in called sh's $1.
NULL
};
这与bourne shell命令sh -c ls '|' wc
相同。
两者都与shell命令sh -c ls | wc
非常不同。那将是
char *const argv[] = {
"sh",
"-c", "sh -c ls | wc", // Command to execute.
NULL
};
您似乎认为|
和wc
已传递给sh
,但事实并非如此。 |
是一个特殊字符,它会产生一个管道,而不是一个参数。
关于退出代码,
Bits 15-8 = Exit code.
Bit 7 = 1 if a core dump was produced.
Bits 6-0 = Signal number that killed the process.
32512 = 0x7F00
所以它没有死于信号,没有产生核心转储,它以代码127(0x7F)退出。
127意味着什么不清楚,这就是它应该伴随错误信息的原因。您尝试执行程序ls | wc
,但没有此类程序。
答案 1 :(得分:0)
您应该执行sh -c 'ls | wc'
。
选项-c
需要一个字符串形式的命令。在shell中当然是有效的,因为产生ls
和将输出重定向到wc
并在单独的shell中启动ls | wc
之间没有区别。