Обычный способ вручную настроить канал, из которого родительский процесс может читать стандартный вывод дочернего процесса, имеет следующие общие шаги:
- родитель создает канал, вызывая
pipe()
- parent
fork()
s - parent закрывает (уточнение: его копия ) конец записи канала
- child дублирует конец записи канала наего стандартный вывод через
dup2()
- дочерний элемент закрывает исходный дескриптор файла для конца записи канала
- (необязательно) дочерний элемент закрывается (уточнение: его копия )конец чтения канала
- дочерний выполняет желаемую команду или выполняет требуемую работу напрямую
Затем родительский объект может прочитать выходные данные дочернего элемента из конца чтения канала.
Функция popen()
делает все это за вас, плюс заключает конец родительского канала в FILE
.Конечно, он может и будет устанавливать канал, идущий в противоположном направлении, если это то, что запрашивает вызывающий.
Вам необходимо понять и оценить, что в процедурной схеме, представленной выше, важно, какие действиякаким процессом выполняется и в каком порядке относительно других действий в том же процессе.В частности, родительский объект не должен закрывать конец записи канала до запуска дочернего элемента , поскольку это делает канал бесполезным.Дочерний объект наследует канал с одним концом, по которому никакие данные не могут быть переданы.
Что касается вашего последнего примера, обратите внимание также, что перенаправление стандартного ввода на конец чтения канала являетсяне является частью процесса для родителей или детей.Тот факт, что ваша труба полузакрыта, так что с нее ничего не читается, просто обледенение на торте.Более того, родительский метод забивает свой собственный стандартный ввод таким образом.Это не обязательно неправильно, но родитель даже не полагается на это.
В целом, однако, есть более широкая картина, которую вы, похоже, не оценили.Даже если вы выполнили перенаправление, которое, как вам кажется, нужно в родительском объекте, чтобы оно могло быть унаследовано дочерним объектом, popen()
выполняет свое собственное перенаправление в канал свое собственное создание .Возвращаемое FILE *
- это средство, с помощью которого вы можете прочитать вывод ребенка.Никакое предыдущее перенаправление вывода, которое вы, возможно, выполнили, не уместно (уточнение: стандартного вывода ребенка).
В принципе, подход, подобный вашему, мог бы использоваться для создания второго перенаправления, идущего другим путем, но при этомТочка удобства фактор popen()
полностью потерян.Было бы лучше пойти по прямому маршруту pipe
/ fork
/ dup2
/ exec
до конца, если вы хотите перенаправить ввод дочернего элемента и .
Применяя все это к первому примеру, вы должны понимать, что, хотя процесс может перенаправлять свои собственные стандартные потоки, он не может установить канал для своего родительского процесса таким образом. Родитель должен предоставить канал, иначе он не знает об этом.И когда процесс дублирует один дескриптор файла на другой, это заменяет оригинал новым, закрывая оригинал, если он открыт.Он не переопределяет оригинал.И, конечно же, в этом случае труба также бесполезна, если ни один из концов больше нигде не открыт.