почему я не могу передать вывод из обоих вызовов execl?

Возможные дубликаты:

Я пытался изучить пайпинг в Linux с использованием dup / dup2 и разветвления последние 3 дня. Я думаю, что у меня это получилось, но когда я вызываю две разные программы из дочернего процесса, мне кажется, что я получаю вывод только из первой вызванной программы. Я не понимаю, почему это и / или что я делаю неправильно. Это мой основной вопрос.

Изменить: Я думаю, что возможное решение состоит в том, чтобы разветвить другого потомка и настроить каналы с dup2, но мне больше всего интересно, почему код ниже не работает. Я имею в виду, что я ожидал бы захватить stderr из первого вызова execl и stdout со второго. Кажется, этого не происходит.

Мой второй вопрос: правильно ли я открываю и закрываю трубы? Если нет, я хотел бы знать, что мне нужно добавить / удалить / изменить.

Вот мой код:

#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <sys/wait.h>

#define READ_END 0
#define WRITE_END 1

void parentProc(int* stdoutpipe, int* stderrpipe);
void childProc(int* stdoutpipe, int* stderrpipe);

int main(){
pid_t pid;
int status;

int stdoutpipe[2]; // pipe
int stderrpipe[2]; // pipe

// create a pipe
if (pipe(stdoutpipe) || pipe(stderrpipe)){
std::cerr << "Pipe failed." << std::endl;
return EXIT_FAILURE;
}

// fork a child
pid = fork();
if (pid < 0) {
std::cerr << "Fork failed." << std::endl;
return EXIT_FAILURE;
}
// child process
else if (pid == 0){
childProc(stdoutpipe, stderrpipe);

}
// parent process
else {
std::cout<< "waitpid: " << waitpid(pid, &status, 0)
<<'\n'<<std::endl;
parentProc(stdoutpipe, stderrpipe);
}

return 0;
}void childProc(int* stdoutpipe, int* stderrpipe){
dup2(stdoutpipe[WRITE_END], STDOUT_FILENO);
close(stdoutpipe[READ_END]);

dup2(stderrpipe[WRITE_END], STDERR_FILENO);
close(stderrpipe[READ_END]);

execl("/bin/bash", "/bin/bash", "foo", NULL);
execl("/bin/ls", "ls", "-1", (char *)0);

//  execl("/home/me/outerr", "outerr", "-1", (char *)0);

//char * msg = "Hello from stdout";
//std::cout << msg;

//msg = "Hello from stderr!";
//std::cerr << msg << std::endl;

// close write end now?
}

void parentProc(int* stdoutpipe, int* stderrpipe){
close(stdoutpipe[WRITE_END]);
close(stderrpipe[WRITE_END]);

char buffer[256];
char buffer2[256];
read(stdoutpipe[READ_END], buffer, sizeof(buffer));
std::cout << "stdout: " << buffer << std::endl;

read(stderrpipe[READ_END], buffer2, sizeof(buffer));
std::cout << "stderr: " << buffer2 << std::endl;

// close read end now?
}

Когда я запускаю это, я получаю следующий вывод:

yfp> g++ selectTest3.cpp; ./a.out
waitpid: 21423

stdout: hB�(6
stderr: foo: line 1: -bash:: command not found

Исходный код двоичного файла «externalr» (закомментированный выше) просто:

#include <iostream>

int main(){
std::cout << "Hello from stdout" << std::endl;
std::cerr << "Hello from stderr!" << std::endl;
return 0;
}

Когда я вызываю «externalr» вместо ls или «foo», я получаю следующий вывод, который я ожидаю:

yfp> g++ selectTest3.cpp; ./a.out
waitpid: 21439

stdout: Hello from stdout

stderr: Hello from stderr!

1

Решение

На execl

Как только вы успешно позвоните execl или любая другая функция из exec семья, оригинальный процесс полностью перезаписан новым процессом. Это означает, что новый процесс никогда не «возвращается» к старому. Если у вас есть два execl Вызовы подряд, единственный способ выполнить второй — это если первый не удастся.

Чтобы запустить две разные команды подряд, вы должны fork один ребенок, чтобы запустить первую команду, wait, fork второй потомок для запуска второй команды, затем (опционально) wait для второго ребенка тоже.

На read

read Системный вызов не добавляет завершающий ноль, поэтому в общем случае вам нужно посмотреть возвращаемое значение, которое сообщает вам количество фактически прочитанных байтов. Затем установите следующий символ в null, чтобы получить строку C, или используйте конструктор диапазона для std::string,

По трубам

Прямо сейчас вы используете waitpid ждать, пока дочерний процесс уже закончился, затем чтение из труб. Проблема в том, что если дочерний процесс выдает много выходных данных, он будет блок потому что канал переполняется, а родительский процесс не читает из него. Результатом будет взаимоблокировка, поскольку дочерний процесс ожидает, пока родитель прочитает, а родительский процесс ожидает завершения дочернего процесса.

Что вы должны сделать, это использовать select ждать поступления ввода либо на ребенка stdout или ребенок stderr, Когда поступит информация, прочитайте ее; это позволит ребенку продолжить. Когда дочерний процесс умирает, вы будете знать, потому что вы получите конец файла на обоих. затем можешь смело звонить wait или же waitpid,

3

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

exec Семейство функций заменяет текущий образ процесса новым образом процесса. Когда вы выполните,

execl("/bin/bash", "/bin/bash", "foo", NULL);

код из текущего процесса больше не выполняется. Вот почему вы никогда не видите результат выполнения

execl("/bin/ls", "ls", "-1", (char *)0);
3

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector