[英]Input redirection problem while using execvp?
我已經實現了一個模擬$ls -l | wc -c
的簡單程序 使用簡單管道和execvp調用執行$ls -l | wc -c
命令。
現在重定向stdin和stdout后,執行程序時,shell提示符消失,等待按下回車鍵。
任何解決這個問題的方法。 Plz批評我的代碼也..
謝謝
/* Create pipe */
ret_val=pipe(pipe_fd);
/*Error check */
if(ERROR==ret_val)
{
perror("Pipe creation error \n");
_exit(FAILURE);
}
/*Fork First Child */
pid_one = fork() ;
if( 0 == pid_one ) /*child process block */
{
/* First sub process */
/*printf("First sub process is %d \n",getpid());*/
/* redirect stdout to pipe's write end for sub process one*/
dup2(pipe_fd[1],1);
/*close pipe read end */
close(pipe_fd[0]);
execvp(cmd_one_tokens[0],cmd_one_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
//exit(10);
}
else /*main process block */
{
/*printf(" Main process is %d \n",getpid());*/
/*Wait for first sub process to finish */
//wait(&status);
/*printf("Exit status of first child is %d \n ", WEXITSTATUS(status) );*/
/*Fork second subprocess */
pid_two = fork();
if( 0 == pid_two ) /*second child process block */
{
/* redirect stdin to pipe's read end for sub process two */
dup2(pipe_fd[0],0);
// close(0); /* close normal stdin */
// dup(pipe_fd[0]); /* make stdib same as pfds[0] */
/*close pipe write end */
close(pipe_fd[1]);
/* Second sub process */
/*printf("Second sub process is %d \n",getpid()); */
execvp(cmd_two_tokens[0] , cmd_two_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
}
else /*main process block */
{
/* printf(" Main process is %d \n",getpid()); */
status=-1; /*reset status */
/*Waiting for the second sub process to finish in No hang fashion */
waitpid ( -1 , &status ,WNOHANG);
/*printf("Exit status of second child is %d \n ", WEXITSTATUS(status) ); */
}
}
在分叉后,您必須在主進程中關閉管道文件描述符。 在關閉它們之前,子進程( wc
)將等待主進程仍然打開的管道上的輸入。 您必須非常小心地關閉管道的所有不需要的端部。
您的代碼沒有按照您的描述執行您想要執行的操作:
你創建一個管道,分叉一個新進程,將它的stdout重定向到管道並讓它執行一些程序(到目前為止一直很好),然后在父進程中等待你的孩子完成,然后只分叉第二個進程,重定向它stdin到管道的另一端,讓它執行另一個程序。
這不是“ls | wc”所做的 - 在shell中它們同時運行。 刪除第一個wait()。
pid_one = fork() ; if( 0 == pid_one ) /*child process block */
你沒有檢查fork(2)
的錯誤返回,這是一個非常現實的可能性。 (用戶可能會kernel.threads-max
他們的RLIMIT_NPROC
限制, kernel.threads-max
,用於保存任務結構的內存不足等)
更慣用的fork(2)
使用如下所示:
if(-1 == (pid = fork()) {
perror("fork");
exit(1); /* or return -1 or similar */
} else if (0 == pid) {
/* executing as child */
} else {
/* parent, pid is child */
}
execvp(cmd_two_tokens[0] , cmd_two_tokens); /* if execvp returns then if must have failed */ printf("Unknown Command \\n ");
請注意, execvp(3)
失敗的原因有很多 ; 簡單地打印“未知命令”可能會讓您的用戶在將來感到非常困惑。 調用perror("execvp");
會更好perror("execvp");
並讓您的用戶有機會發現他們的execvp(3)
調用失敗的真正原因。
waitpid ( -1 , &status ,WNOHANG);
在這里使用WNOHANG
可能很危險; 如果系統“正常”運行,您的父母可能會在孩子甚至有機會開始執行之前獲得此代碼。 因為如果沒有孩子退出,你已經要求它立即返回,孩子可能會在最終退出時變成僵屍 - 你的代碼沒有機會再次等待孩子。
我不確定最佳解決方案是什么:如果您使用SA_NOCLDWAIT
進行sigaction(2)
以避免完全創建僵屍,您將沒有機會收集孩子的退出狀態。 安裝SIGCHLD
信號處理程序可能會干擾進程的其余部分; 您的客戶可能有理由自行設置。 使用阻塞waitpid(2)
可能會停止其他地方的處理。 並且使用非阻塞waitpid(2)
意味着您仍然必須在某個時間收集孩子的狀態,可能通過輪詢。 (但是在這種情況下你不能使用-1
作為pid
,因為你可能會意外地收獲另一個子進程。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.