在我的程序中,我正在执行给定的命令并获取结果(日志和退出状态)。 另外我的程序必须支持shell特定的命令(即包含shell特定字符〜(tild),|(pipe),*)的命令。 但是当我尝试运行sh -c ls | wc
sh -c ls | wc
在我的主目录通过我的程序失败,其退出状态是32512,也在stderrstream"sh: ls | wc: command not found"
被打印。
但有趣的是命令sh -c ls | wc
如果我在shell中运行它, sh -c ls | wc
工作正常。
问题是什么? 或者更可取的是,如何通过我的程序运行特定于shell的命令(例如,哪个命令与哪个参数运行)?
下面的代码部分在fork()后面是子部分。 它执行命令。
tokenized_command
是std::vector<std::string>
其中在我的情况下, "sh", "-c", "ls", "|", "wc"
被存储,也试图在那里存储"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); }
PS
我知道使用system(command)
而不是execvp
可以解决我的问题。 但system()
等待直到命令完成,这对我的程序来说不够好。 而且我也确信在system()
实现中使用了exec-family函数,所以这个问题也可以通过exec
来解决,但我不知道如何。
execvp
获取可执行文件的路径,以及用来启动该可执行文件的参数。 它不需要bourne shell命令。
ls | wc
ls | wc
是一个bourne shell命令(等等),并且由于使用了一个管道,它不能被分解成可执行文件和一些参数的路径。 这意味着它不能使用execvp
执行。
要使用execvp
执行bourne shell命令,必须执行sh
并传递-c
和参数命令。
所以你要执行ls | wc
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
sh -c ls '|' wc
。
和shell命令sh -c ls | wc
完全不同 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)退出。
这意味着什么不清楚,这就是为什么它应该伴随着一个错误信息。 您试图执行程序ls | wc
ls | wc
,但是没有这样的程序。
你应该执行sh -c 'ls | wc'
sh -c 'ls | wc'
。
选项-c
需要一个字符串形式的命令。 在shell中当然是有用的,因为在产生ls
和重定向输出到wc
和启动ls | wc
之间没有区别ls | wc
ls | wc
在单独的shell中。