Игрушечная оболочка не правильно обвязана

Я не собираюсь лгать. Это домашнее задание. Однако, насколько я понимаю, очки ушли, детка, ушли. Прямо сейчас я просто ищу ответ, потому что, я думаю, я могу быть безумен.

Цель этой программы — выполнить команду ps -A | grep (inputstring) | wc -l таким же образом, как это делает оболочка. Итак, я порождаю процессы и заставляю их ждать друг друга. Новейший процесс, правнук, execlp("ps","ps","-A",NULL) который заменяет собой ps -A процесс. Перед этим execlp, Я уверен, что его стандартный вывод идет на выходе канала. Следующий процесс в очереди wait()и уже настроил себя так, чтобы входной канал перешел в стандартный вход, а стандартный выход — в выходной канал, и он выполнит grep и так далее.

Я почти уверен, что все настроено правильно. И все же … программа делает. Не. Работа.

#include <stdlib.h>
#include <iostream>
#include <string>

#define MAXLINE 1500
#define READ 0
#define WRITE 1

using namespace std;

int main( int argc, char** argv ) {
//* start of input block
if ( argc != 2 ) {
cout << "Usage: ./a.out arg1" << endl;
return 0;
}
string in = argv[1];
// end of input block */
int pipeA[2], pipeB[2], pid, stat;

// get our first set of pipes
if ( pipe(pipeA) < 0 ) {
cerr << "Pipe error.\n";
exit(-1);
}
if ( pipe(pipeB) < 0 ) {
cerr << "Pipe error.\n";
exit(-1);
}

// make the first fork
if ( (pid = fork() ) < 0 ) { cerr << "Fork error.\n"; exit(-1); }

if ( pid > 0 ) {    // parent case
wait(&stat);
} else {            // child case
if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
if ( pid > 0 ) {    // child
wait(&stat);
dup2(pipeA[READ],READ);
execlp("wc","wc","-l",NULL);
} else {    // grand-child
if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
if ( pid > 0 ) {    // still grand-child
wait(&stat);
dup2(pipeB[READ],READ);
dup2(pipeA[WRITE],WRITE);
close(pipeB[READ]);
execlp("grep","grep",in.c_str(),NULL);
} else {    // great grand-child
dup2(pipeB[WRITE],WRITE); // t now goes to pipeB[1]
close(READ);
close(pipeB[READ]);
execlp("ps", "ps", "-A", NULL);
}
}
}
return 0;
}

РЕДАКТИРОВАТЬ: Изменен на двухтрубный вариант моего кода.

1

Решение

Я практически уверен, что это то, что вы пытаетесь сделать. Заранее извиняюсь за небрежное кодирование. здесь уже поздно, и я действительно должен спать прямо сейчас:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>

#define READ 0
#define WRITE 1

// ps -A | grep argv[1] | wc -l

int main( int argc, char** argv )
{
//* start of input block
if ( argc != 2 )
{
std::cout << "Usage: ./a.out arg1" << std::endl;
return 0;
}

// make local copy of argument
std::string in = argv[1];
int fd1[2], fd2[2], pid;

// allocate two pipe sets
if (pipe(fd1) < 0 || pipe(fd2) < 0)
{
perror("Failed to create pipe.");
return EXIT_FAILURE;
}

// launch first child process.
if ((pid = fork()) < 0)
{
perror("Failed to fork child(1)");
return EXIT_FAILURE;
}

if (pid == 0)
{
// wc -l process.
//  stdin  = fd2(read)
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
execlp("wc","wc","-l",NULL);
}

// fork again. this time for grep
if ((pid = fork()) < 0)
{
perror("Failed to fork child(2)");
return EXIT_FAILURE;
}

if (pid == 0)
{
// grep argv[1] process.
//  stdin  = fd1(read)
//  stdout = fd2(write)
close(fd1[WRITE]);
close(fd2[READ]);
dup2(fd2[WRITE], STDOUT_FILENO);
dup2(fd1[READ], STDIN_FILENO);
execlp("grep", "grep", in.c_str(), NULL);
}

//  fork once more. this time for ps -A
if ((pid = fork()) < 0)
{
perror("Failed to fork child(3)");
return EXIT_FAILURE;
}

if (pid == 0)
{
// ps -A process.
//  stdout = fd1(write)
close(fd2[WRITE]);
close(fd2[READ]);
close(fd1[READ]);
dup2(fd1[WRITE], STDOUT_FILENO);
execlp("ps", "ps", "-A", NULL);
}

int stat=0;
wait(&stat);

return EXIT_SUCCESS;
}

В моей системе ps -A сообщает 141 строчку, из них 41 слово System где-то внутри, проверяется просто бегом ps -A | grep System | wc -l, Приведенный выше код генерирует точно такой же вывод.

Надеюсь, это поможет вам.

1

Другие решения

Я не уверен, но, возможно, вызов dup2 перед ожиданием ребенка решит проблему с конвейером.

Причина, по которой я не уверен, заключается в том, что обычно stdin и stdout буферизуются, поэтому я полагаю, что даже если вы подключите их с помощью канала после того, как ребенок завершит работу, вы должны получить те же результаты, но, возможно, (если кто-то знает ответ на поправьте меня, пожалуйста) буферы для stdin и stdout стираются с окончанием дочернего процесса.

Кроме того, не могли бы вы обновить код в вашем вопросе, чтобы он содержал модифицированный код с двумя наборами каналов?

0

По вопросам рекламы [email protected]