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.
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;
}
}
}
}
Example Output:
nick@nick-VirtualBox ~/Documents/Assign10 $ ./z1615629
Command One (or quit): ls -l
Command Two: wc
Command One (or quit): Command One (or quit): quit
Example Output:
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
I know it doesn't address the question, but here's the original code C++-ified.
I've taken care to remain C++03 compatible. I only assume TR1 for the bind (allthough the incantation with mem_fun_ref should be pretty easy to write).
Note the reduction in size: removes 88 LoC (>50%)
Disclaimer It compiles, I haven't run it (I wouldn't know what input to feed it, and how, anyway.)
Because you don't use functions, you have asymmetric behaviour in your command prompting and reading loops:
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.You need to close the pipes in the parent process. You also need to
wait()
at:using: