Подтвердить что ты не робот

Перенаправление вывода exec в буфер или файл

Я пишу программу на C, где я fork(), exec() и wait(). Я хотел бы взять вывод программы, которую я выполнил, чтобы записать ее в файл или буфер.

Например, если я exec ls, я хочу написать file1 file2 etc в буфер/файл. Я не думаю, что есть способ читать stdout, так значит ли это, что я должен использовать трубку? Существует ли здесь общая процедура, которую я не смог найти?

4b9b3361

Ответ 1

Для отправки вывода в другой файл (я оставляю проверку ошибок, чтобы сосредоточиться на важных деталях):

if (fork() == 0)
{
    // child
    int fd = open(file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    dup2(fd, 1);   // make stdout go to file
    dup2(fd, 2);   // make stderr go to file - you may choose to not do this
                   // or perhaps send stderr to another file

    close(fd);     // fd no longer needed - the dup'ed handles are sufficient

    exec(...);
}

Для отправки вывода в канал, чтобы вы могли читать вывод в буфер:

int pipefd[2];
pipe(pipefd);

if (fork() == 0)
{
    close(pipefd[0]);    // close reading end in the child

    dup2(pipefd[1], 1);  // send stdout to the pipe
    dup2(pipefd[1], 2);  // send stderr to the pipe

    close(pipefd[1]);    // this descriptor is no longer needed

    exec(...);
}
else
{
    // parent

    char buffer[1024];

    close(pipefd[1]);  // close the write end of the pipe in the parent

    while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
    {
    }
}

Ответ 2

Вам нужно решить, что именно вы хотите сделать - и лучше объясните это немного более четко.

Вариант 1: Файл

Если вы знаете, к какому файлу вы хотите выполнить вывод выполненной команды, выполните следующие действия:

  • Убедитесь, что родитель и ребенок согласны с именем (родительский решает имя перед форкировкой).
  • Родительские вилки - у вас есть два процесса.
  • Ребенок реорганизует вещи так, чтобы файловый дескриптор 1 (стандартный вывод) попадал в файл.
  • Обычно вы можете оставить стандартную ошибку самостоятельно; вы можете перенаправить стандартный ввод с /dev/null.
  • Ребенок затем выполняет соответствующую команду; указанная команда запускается, и любой стандартный вывод идет в файл (это основное перенаправление ввода-вывода оболочки).
  • Выполненный процесс завершается.
  • Между тем, родительский процесс может принять одну из двух основных стратегий:
    • Откройте файл для чтения и продолжайте читать, пока он не достигнет EOF. Затем необходимо дважды проверить, умер ли ребенок (так что больше не будет данных для чтения) или зависать, ожидая большего ввода от ребенка.
    • Подождите, пока ребенок умрет, а затем откройте файл для чтения.
    • Преимущество первого заключается в том, что родитель может выполнять некоторую часть своей работы, пока ребенок также работает; преимущество второго заключается в том, что вам не нужно лезть с системой ввода/вывода (повторное чтение предыдущего EOF).

Вариант 2: Труба

Если вы хотите, чтобы родительский элемент читал выходные данные дочернего элемента, организуйте дочерний процесс для его вывода обратно родительскому элементу.

  • Используйте popen(), чтобы сделать это простым способом. Он запустит процесс и отправит результат в ваш родительский процесс. Обратите внимание, что родительский элемент должен быть активным, пока дочерний элемент генерирует результат, поскольку в канале имеется небольшой размер буфера (часто 4-5 КБ), и если дочерний элемент генерирует больше данных, чем тот, который родитель не читает, он будет блокироваться до тех пор, пока родительский читает. Если родитель ждет, пока ребенок умрет, у вас есть тупик.
  • Используйте pipe() и т.д., чтобы сделать это трудным путем. Родительский вызов pipe(), затем вилки. Ребенок разбирает водопровод, так что конец записи трубы является его стандартным выходом и гарантирует, что все остальные дескрипторы файлов, относящиеся к трубе, будут закрыты. Это может использовать системный вызов dup2(). Затем он выполняет требуемый процесс, который отправляет свой стандартный вывод по трубе.
  • Между тем, родитель также закрывает нежелательные концы трубы, а затем начинает чтение. Когда он получает EOF на трубе, он знает, что ребенок закончил и закрыл трубу; он также может закрыть его конец.

Ответ 3

Поскольку вы похожи на то, что собираетесь использовать это в среде linux/cygwin, вы хотите использовать popen. Это как открытие файла, только вы получите исполняемые программы stdout, чтобы вы могли использовать обычные fscanf, fread и т.д.

Ответ 4

После форкирования используйте dup2(2), чтобы дублировать файл FD в stdout FD, затем exec.