分叉和管道C ++奇怪的输出

时间:2012-11-20 21:49:57

标签: c++ linux fork pipe

我要写一个带有2个命令及其参数(最多5个)的赋值,它会将一个输出管道输出到另一个。然后循环,再次请求两个命令,直到退出为止。

我遇到的问题是在第二个循环中输入值后,会发生奇怪的事情,比如在输入第二个命令后输出“Enter Command 1”(两者都出现在同一行)。我还注意到输入ls -l然后cat工作,例如,但输入ls -l然后wc会导致问题。有人会介意看看并可能帮助我吗?我整天都在工作,我还有一个多小时的时间来完成它。

侧注:是的,我意识到执行命令设置有点愚蠢,但我没时间,没有时间摆弄它。它有效。

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sstream>
using namespace std;

int main(){
//Our imput strings that the user enters.
string input1;
string input2;

//Temporary string.
string s;  

//Array to hold the items passed in.
string arg1[6];
string arg2[6];

//A count of how many items they passed in.
int carg1;
int carg2;

//Loop until quit.
while(true){
    //Set all our values to empty/zero
    carg1 = 0;
    carg2 = 0;
    input1.clear();
    input2.clear();

    //Prompt for first command.
    while(input1.empty()){
        cout << "Command One (or quit): ";
        getline(cin, input1);
    }

    //Split the string by the space to get the pieces of the command.
    istringstream iss1(input1); 
    while (getline(iss1, s, ' ')) {
        arg1[carg1] = s;
        carg1++;
    }

    //Check if command is quit and exit if true.
    if(arg1[0].compare("quit") == 0){
        return 0;
    }

    //Prompt for command 2.
    while(input2.empty()){  
        cout << "Command Two: ";
        cin >> input2;
    }

    //Once again, split based on spaces.
    istringstream iss2(input2); 
    while (getline(iss2, s, ' ')) {
        //arg2.push_front(s);
        arg2[carg2] = s;
        carg2++;
    }

    //Initialize the pipe.
    int pipefd[2];
    if(pipe(pipefd) == -1){
        perror("Pipe");
        exit(EXIT_FAILURE);
    }

    //Create the fork to two processes.
    int pid = fork();

    //Switch to check for parent and child.
    switch(pid){
        case 0: //Child process
            //Close the read pipe and standard input.
            close(pipefd[0]);
            close(1);

            //Copy data
            dup(pipefd[1]);

            //Close other end of the pipe
            close(pipefd[1]);

            //Execute the first command. Based on how many params, call different ones.
            switch(carg1){
                case 1:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), (char*)NULL);
                    break;
                case 2:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), arg1[1].c_str(), (char*)NULL);
                    break;
                case 3:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), arg1[1].c_str(), arg1[2].c_str(), (char*)NULL);
                    break;
                case 4:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), arg1[1].c_str(), arg1[2].c_str(), arg1[3].c_str(), (char*)NULL);
                    break;
                case 5:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), arg1[1].c_str(), arg1[2].c_str(), arg1[3].c_str(), arg1[4].c_str(), (char*)NULL);
                    break;
                case 6:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), arg1[1].c_str(), arg1[2].c_str(), arg1[3].c_str(), arg1[4].c_str(), arg1[5].c_str(), (char*)NULL);
                    break;
                case 7:
                    execlp(arg1[0].c_str(), arg1[0].c_str(), arg1[1].c_str(), arg1[2].c_str(), arg1[3].c_str(), arg1[4].c_str(), arg1[5].c_str(), arg1[6].c_str(), (char*)NULL);
                    break;
            }
            return 0;
        case -1: //Error
            perror("fork");
            exit(EXIT_FAILURE);
        default: //Parent Process
            //Wait for initial command to execute.
            wait(&pid);

            //Fork into two processes.
            int pid2 = fork();

            //Switch based on child and parent.
            switch(pid2){
                case 0: //Child process
                    //Close write end of pipe and standard output.
                    close(pipefd[1]);
                    close(0);

                    //Duplicate to standard input
                    dup(pipefd[0]);

                    //Close read end.
                    close(pipefd[0]);

                    //Execute proper command based on params
                    switch(carg2){
                        case 1:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), (char*)NULL);
                            break;
                        case 2:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), arg2[1].c_str(), (char*)NULL);
                            break;
                        case 3:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), arg2[1].c_str(), arg2[2].c_str(), (char*)NULL);
                            break;
                        case 4:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), arg2[1].c_str(), arg2[2].c_str(), arg2[3].c_str(), (char*)NULL);
                            break;
                        case 5:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), arg2[1].c_str(), arg2[2].c_str(), arg2[3].c_str(), arg2[4].c_str(), (char*)NULL);
                            break;
                        case 6:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), arg2[1].c_str(), arg2[2].c_str(), arg2[3].c_str(), arg2[4].c_str(), arg2[5].c_str(), (char*)NULL);
                            break;
                        case 7:
                            execlp(arg2[0].c_str(), arg2[0].c_str(), arg2[1].c_str(), arg2[2].c_str(), arg2[3].c_str(), arg2[4].c_str(), arg2[5].c_str(), arg2[6].c_str(), (char*)NULL);
                            break;
                    }
                    return 0;
                case -1: //Error
                    perror("fork");
                    exit(EXIT_FAILURE);
                default: //Parent Process
                    //wait(&pid2);
                    break;
            }
    }   
}
}

示例输出

nick@nick-VirtualBox ~/Documents/Assign10 $ ./z1615629
Command One (or quit): ls -l
Command Two: wc
Command One (or quit): Command One (or quit): quit

示例输出

nick@nick-VirtualBox ~/Documents/Assign10 $ ./z1615629
Command One (or quit): ls -l
Command Two: cat
Command One (or quit): Command One (or quit): 
total 32
-rwxr-xr-x 1 nick nick 13358 Nov 20 15:46 z1615629
-rw-r--r-- 1 nick nick  4544 Nov 20 15:46 z1615629.cxx
-rw-r--r-- 1 nick nick  8104 Nov 20 15:46 z1615629.o

2 个答案:

答案 0 :(得分:1)

因为您不使用函数,所以在命令提示和读取循环中存在不对称行为:

//Prompt for first command.
while (input1.empty()){
    cout << "Command One (or quit): ";
    getline(cin, input1);
}

...

//Prompt for command 2.
while (input2.empty()){  
    cout << "Command Two: ";
    cin >> input2;
}

第二个命令只包含一个单词。新线被遗忘,在下一个周期给你双重提示。在第二个提示循环中使用getline(cin, input2)。如果你使用函数,你就会获得一致性 - 函数可以让生活更轻松,而不是更难。

您需要关闭父进程中的管道。您还需要wait() at:

          default: //Parent Process
                //wait(&pid2);
                break;

使用:

          default: // Parent process
               close(pipefd[0]);
               close(pipefd[1]);
               while (wait(0) != -1)
                   ;
               break;

答案 1 :(得分:1)

我知道它没有解决这个问题,但这里是原始代码C ++ - ified。

我已经注意保持C ++ 03兼容。我只假设绑定的TR1(尽管mem_fun_ref的咒语应该很容易写)。

请注意缩小尺寸:删除88 LoC(&gt; 50%)

#include <iostream>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <tr1/functional>
using namespace std;

void execute(std::vector<string> const& arg1) {
    vector<char const*> argv(arg1.size());
    transform(arg1.begin(), arg1.end(), argv.begin(), tr1::bind(&std::string::c_str, tr1::placeholders::_1));
    argv.push_back(NULL);
    execvp(argv[0], (char* const*) &argv[0]); // TODO FIXME error handling?
    exit(EXIT_FAILURE);
}

std::vector<string> getinput(std::string prompt) {
    vector<string> result;
    string input;
    //Prompt for first command.
    while(input.empty()) {
        cout << prompt;
        getline(cin, input);
    }
    //Split the string by the space to get the pieces of the command.
    {
        istringstream iss(input);
        copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(result));
    }
    return result;
}

int main() {
    //Loop until quit.
    while(true) {
        const std::vector<string> cmd1 = getinput("Command One (or quit): ");
        if(cmd1.empty() || cmd1[0] == "quit") {
            return 0;
        }
        const std::vector<string> cmd2 = getinput("Command Two: ");

        //Initialize the pipe.
        int pipefd[2];
        if(pipe(pipefd) == -1) {
            perror("Pipe");
            exit(EXIT_FAILURE);
        }
        int pid = fork();               //Create the fork to two processes.
        switch(pid) {                   // Switch to check for parent and child.
            case 0:                     // Child process
                close(pipefd[0]);       // Close the read pipe and standard input.
                close(1);
                dup(pipefd[1]);         // Copy data
                close(pipefd[1]);       // Close other end of the pipe
                execute(cmd1);
                return 0;
            case -1:                    // Error
                perror("fork");
                exit(EXIT_FAILURE);
            default:                    // Parent Process
                wait(&pid);             // Wait for initial command to execute.
                int pid2 = fork();      // Fork into two processes.
                switch(pid2) {          // Switch based on child and parent.
                case 0:                 // Child process
                    close(pipefd[1]);   // Close write end of pipe and standard output.
                    close(0);
                    dup(pipefd[0]);     // Duplicate to standard input
                    close(pipefd[0]);   // Close read end.
                    execute(cmd2);      // Execute proper command based on params
                    return 0;
                case -1:                // Error
                    perror("fork");
                    exit(EXIT_FAILURE);
                default:                // Parent Process
                    //wait(&pid2);
                    break;
                }
        }
    }
}

免责声明它编译,我没有运行它(我不知道输入它的输入,以及如何,无论如何。)