分叉和管道C ++奇怪的输出 [英] Forking And Piping C++ Strange Ouput

查看:96
本文介绍了分叉和管道C ++奇怪的输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要编写一个包含2个命令及其参数(最多5个)的赋值,它将一个输出传递给另一个.然后它将循环,再次询问两个命令,直到输入quit.

I am to write an assignment that takes 2 commands and their arguments (up to 5) and it will pipe the output of one to the other. It will then loop, again asking for two commands until quit is entered.

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

The problem I am having is that after entering values on the second loop, weird things happen, such as outputting "Enter Command 1" right after entering the second command (both appear on the same line). I also noticed that entering ls -l and then cat works for example, but entering ls -l then wc causes issues. Would someone mind taking a look and possibly helping me with it? I have been working at it all day and I have a little over an hour left to finish it.

侧面注:是的,我知道执行命令的设置有点愚蠢,但是我没时间了,也没有时间摆弄它.可以.

Side Note: Yes, I realize the execute command setup is a bit stupid, but I am out of time and don't have time to fiddle with it. It works.

#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

推荐答案

由于不使用函数,因此在命令提示符和读取循环中存在不对称行为:

Because you don't use functions, you have asymmetric behaviour in your command prompting and reading loops:

//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).如果使用函数,您将获得一致性-函数使生活更轻松,而不是更辛苦.

The second command only ever contains a single word. The newline is left behind, giving you the double prompt on the next cycle. Use getline(cin, input2) in the second prompt loop. If you use functions, you get consistency — functions make life easier, not harder.

您需要在父进程中关闭管道.您还需要在以下位置wait()

You need to close the pipes in the parent process. You also need to wait() at:

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

使用:

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

这篇关于分叉和管道C ++奇怪的输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆