Перенаправление вывода exec в буфер или файл
Я пишу программу на C, где я fork()
, exec()
и wait()
. Я хотел бы взять вывод программы, которую я выполнил, чтобы записать ее в файл или буфер.
Например, если я exec ls
, я хочу написать file1 file2 etc
в буфер/файл. Я не думаю, что есть способ читать stdout, так значит ли это, что я должен использовать трубку? Существует ли здесь общая процедура, которую я не смог найти?
Ответы
Ответ 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.