2017-03-01 84 views
1

所以我在写一个UNIX shell一类矿,基本上我参加一个参数,如果该参数具有“&”在它的结束,然后我需要的父进程调用等待();。有问题与派生进程

我在这里的问题是,该方案应接受输入,直到我键入exit,所以一切都在一个“而”循环。事情办得完美,直到我在它的结束通话与“&”命令,然后我可以看到,父进程结束,那么孩子结束,但我不是在我的正常提示接受的输入是“osh>”。

所以基本上这里是我的正常输出,当我运行一个简单的命令:

osh> ls -l 
child:0 
a.out main main.cpp main.cpp~ 
parent: 8695 

但是当我在最后运行带有“&”命令出现这种情况:

osh> ls -l & 
parent: 27082 
osh> child:0 
total 44 
-rwxr-xr-x 1 myuser users 10368 Mar 1 14:46 a.out 
-rwxr-xr-x 1 myuser users 23368 Mar 1 14:00 main 
-rw-r--r-- 1 myuser users 1658 Mar 1 14:46 main.cpp 
-rw-r--r-- 1 myuser users 1676 Mar 1 14:45 main.cpp~ 
<cursor is here accepting commands, but no osh> prompt> 

如果任何人有任何意见或建议,将不胜感激。我觉得这只是一个小错误,但我已经多次运行调试器,找不到任何东西。我只是没有那么多的经验。下面是完整的代码来看看:

#include <stdio.h> 
#include <unistd.h> 
#include <iostream> 
#include <string.h> 
#include <string> 
#include <cstring> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <stdlib.h> 

#define MAX_LINE 80 //the maximum length command 

using namespace std; 

int main() 
{ 
    char* args[MAX_LINE/2 + 1]; //command line arguments 
    char str[41]; //intitialize string for input 
    int should_run = 1; //flag to determine when to exit program 
    bool status; //status of whether or not an ampersand is in the passed argument 

    while (should_run) { 
    int index = 0; 

    cout << "osh> "; 
    fflush(stdout); 

    cin.getline(str, 41); 

    args[index] = strtok(str, " "); 

    while (args[index] != NULL) { 
     index++; 
     args[index] = strtok(NULL, " "); 
    } 

    if (strcmp (args[0], "exit") == 0) //in input is "exit", exit the while loop 
     break; 

    if (*args[index - 1] == '&') //check whether to run processes concurrently 
     status = true; 

    args[index - 1] = NULL; //remove & to make sure arguments are valid 

    // (1) fork a child process using fork() 
    pid_t pid = fork(); 

    if (pid < 0) { //error handling 
     perror("Fork Failed."); 
     break; 
     } 
    // (2) the child process will invoke execvp() 
    if (pid == 0) { 
     //child process 
     cout << "child:" << pid << endl; 
     if (execvp (args[0], args) == -1) { 
     perror ("exec"); 
     } 
    } 

    // (3) if command didn't included &, parent will invoke wait() 
    //parent process 
    if (pid > 0) { 
     // parent process 
     if (!status) { 
     wait(0); 
     } 
     cout << "parent: " << pid << endl; 
    } 
    } 

    return 0; 
} 

编辑:也刚刚意识到我的第二个输出我张贴,它表明“职业安全与卫生>”父进程后,第二次,不知道该如何形容这个错误。

+0

这几乎是如何在每个其他的Unix shell中工作。 – immibis

+0

任何不使用C编写它的原因,它几乎都是? –

+0

@NeilButterworth对C++ – HOAX

回答

3

不,你已经在命令提示符:

osh> child:0 
total 44 

这是你的命令,提示,osh>提示。

你这里的问题是,您的计算机做你告诉它做什么,而不是你想要它做的事。你的代码(有一个不相关的,主要的错误,我现在会得到的)说,不要等到子进程结束,然后继续,如果输入&

而这到底发生了什么。子进程已经开始,您的父进程立即发出下一个osh>提示。而且,在儿童流程甚至产生任何输出的变化之前,它做得非常快。因此,在osh>提示符后,子进程的输出将显示在您的终端上。由于你的父进程已经产生了它的提示符,它现在正在等待你的下一个输入,并且没有理由不继续等待,在子进程终止之后,并且完成了它的输出。

这回答了什么事你提示的问题。你没有解释你预期会发生什么,所以没有什么可以说的。但如果您想要再次发出提示,在子进程终止后,您可以通过正确处理SIGCHLD信号来完成此操作。有关更多信息,请参阅C++书籍。

至于你无关的错误,它实际上是两个错误:

if (*args[index - 1] == '&') 
    status = true; 

args[index - 1] = NULL; //re 

首先BUG:任何以'&'开始,而不是仅仅“&”本身,就会触发后台作业的行为。

第二个错误:如果没有输入'&',这段代码仍然会截断输入的最后一个单词。这就是为什么当你输入命令ls -l时,你最终执行了ls,并从第一个命令中得到结果输出。

+0

谢谢你的长时间回应,将查看我的错误。 – HOAX

+0

注意比在POSIX shell(Bash,Korn,...)中,一个'&'标记一个命令的结尾,除非它后面跟着另一个'&&'(好吧,它仍然标记命令的结尾 - 它是一个不同的终止符虽然) - 或者除非它是使用'&'作为第一个字符的晦涩[Bash重定向](https://www.gnu.org/software/bash/manual/bash.html#Redirections)语法之一(' &>和亲戚)。 –

+0

嗨,山姆,我能否使用waitpid而不是直接处理SIGCHLD?很难理解这个概念 – HOAX