execvp叉:等待标准输出
问题描述:
我编码一个简单的Linux壳C.execvp叉:等待标准输出
有时用叉子,然后执行无阻塞命令时 - 我的下一个printf
消失。我猜这是因为子进程正在写入stdout。
如果我使用waitpid
就没有问题 - 因为我的下一个printf只会在子进程终止后打印。有时用户需要执行非阻塞命令 - 然后我不会使用waitpid
- 然后我的下一个printf
将消失。
如果我使用sleep(1)
它也解决了这个问题。但我想知道是否有一种更优雅的方式来实现这一点。
int main(int argc, char *argv[], char *env[])
{
pid_t child_pid;
int status;
if((child_pid = fork()) < 0)
{
perror("fork failure");
exit(1);
}
if(child_pid == 0)
{
printf("\nChild: I am a new-born process!\n\n");
char *sd[] = {"ls", "-l", NULL};
execvp(sd[0], sd);
}
else
{
printf("THIS LINE SOMETIMES DISAPPEAR");
}
return 0;
}
答
正常情况下,当您期望它返回输出时,您将为显式IO管道设置一个显式的IO管道。当你fork和exec子进程时,它会继承父进程的文件描述符。所以你想通过调用pipe(2)为孩子的输出创建一个单向管道。在孩子中,在执行命令之前,将标准输出和标准错误重定向到管道的写入端(使用dup2(2))。在父项中,您只需从管道的读取端中读取,直到EOF并根据输出执行任何操作。然后你等待孩子退出。
这里是这样做没有任何错误处理的例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
pid_t child;
int p[2], to_parent, from_child;
int child_status;
char buffer[1024];
ssize_t nread;
/* create a unidirectional pipe
* - child process will write to p[0]
* - parent process will read from p[1]
*/
pipe(p);
from_child = p[0];
to_parent = p[1];
child = fork();
if (child == 0) {
/* child */
/* close parent end of pipe */
close(from_child);
/* close unnecessary file descriptors */
close(STDIN_FILENO);
/* redirect standard output & error to pipe */
dup2(STDOUT_FILENO, to_parent);
dup2(STDERR_FILENO, to_parent);
/* exec or die */
execlp("ls", "ls", "-l", NULL);
exit(EXIT_FAILURE);
}
/* parent */
/* close child end of pipe */
close(to_parent);
/* read output from child until EOF */
while ((nread=read(from_child, &buffer[0], sizeof(buffer))) > 0) {
write(STDOUT_FILENO, &buffer[0], nread);
}
buffer[0] = '\n';
write(STDOUT_FILENO, &buffer[0], 1);
close(from_child);
/* wait for child */
wait(&child_status); /*mindlessly copied from stack overflow*/
if (WIFEXITED(child_status)) {
printf("child %lu exited with code %d\n",
(unsigned long)child, WEXITSTATUS(child_status));
} else if (WIFSIGNALED(child_status)) {
printf("child %lu terminated due to signal #%d%s\n",
(unsigned long)child, WTERMSIG(child_status),
WCOREDUMP(child_status) ? ", core dumped" : "");
} else if (WIFSTOPPED(child_status)) {
printf("child %lu stopped due to signal #%d\n",
(unsigned long)child, WSTOPSIG(child_status));
}
return 0;
}
你必须要小心关闭不必要的文件描述符。例如,将管道的to_parent
一侧打开将导致父级的读取永远不会返回EOF。